• mongodb快速入门


    通过mongdb初始,我们对mongodb有了一个基本的认识,接下来看一下究竟如何使用。
    本部分包含的内容包括:
    1、mongodb在mac的安装,命令行及客户端工具的简单介绍;
    2、在spring中如何使用mongodb,增删改查示例;
    3、mongodb原生api的使用,增删改查示例;
    4、mongodb连接池的学习;

    -------------------------------------------------------------------------------------------------------------------------------------------------
    1、下载安装及工具简单介绍
    1、从官网下载安装包https://www.mongodb.com/download-center,解压到本地合适文件夹;
    2、手动创建data目录以及logs跟logs/mongodb.log文件;
    3、在mongodb安装目录创建etc目录,并在其下创建mongodb.conf文件,内容见下;
    4、配置环境变量,export PATH=${PATH}:/software/mongodb-osx-x86_64-4.0.10/bin;
    5、到bin目录执行./mongod -f ../etc/mongod.conf启动,或者nohup ./mongod -f ../etc/mongod.conf & 后台启动;
    mongodb.conf内容如下:
    #mongodb config file
    dbpath=/software/mongodb-osx-x86_64-4.0.10/data/db/ #数据存放目录
    logpath=/software/mongodb-osx-x86_64-4.0.10/logs/mongod.log #日志存放目录
    logappend = true #以天为单位,自动切割日志
    port = 27017
    fork = true
    auth = false
    下载官方工具MongoDB Compass,启动后进行连接,过程略;
    命令行及compass工具使用:
    命令行:
    1、连接数据库,./mongo ip地址:端口号,连接本地可以省略地址跟端口号,注意启动命令是mongod,连接命令是mongo

     

    2、查看当前有几个数据库,show dbs ,类似于mysql的show database;
    3、切换数据库,use 库名;
    4、查看库中所有表,show collections;若当前库没有表,则显示为空;
    5、往表中随便插入一条数据,db.myusers.insert({"name":"张三"})

     这里我们注意一下,show dbs的时候,并没有mytest这个库,我们直接use mytest,mongodb并没有报错,而且我们可以直接insert;这一点跟mysql是不一样的,mongodb可以不用创建库,直接use之后insert的时候回自动创建该库,若没有insert操作,该库并不会实际创建;而且可以看到,对于插入的数据,mongodb自动生成了id;

    compass连接本地,可以在左侧看到当前实例的所有库,右侧则为查询展示内容,list为mongo的josn视图,table为将数据展示为传统的关系库表视图;,上方的filter可以书写查询条件,另外还有查询的执行计划,索引等内容,稍后详述;我们刚才加入的数据:
    2、spring 集成mongodb使用
      目标:利用spring提供的mongodb的api实现对单表的增删改查
      1、创建spring boot项目,pom文件添加
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongo-java-driver</artifactId>
        <version>3.8.0</version>
    </dependency>
    

      2、application.yml中添加

    spring:
      data:
        mongodb:
          uri: mongodb://localhost:27017/wzy
      3、初始化数据:
      数据脚本如下:本文所采用的数据已被本地多次测试修改,但结构未发生变化,脚本参考如下:
    db.users.drop();
    var user1 = {
            "username" : "张三",
            "country" : "china",
            "address" : {
                    "aCode" : "411000",
                    "add" : "长沙"
            },
            "favorites" : {
                    "movies" : ["杀破狼2","战狼","雷神1"],
                    "cites" : ["长沙","深圳","上海"]
            },
            "age" : 18,
    	"salary":NumberDecimal("18889.09"),
           "lenght" :1.79
    };
    var user2 = {
            "username" : "李四",
            "country" : "English",
            "address" : {
                    "aCode" : "311000",
                    "add" : "地址"
            },
            "favorites" : {
                    "movies" : ["复仇者联盟","战狼","雷神1"],
                    "cites" : ["西安","东京","上海"]
            },
            "age" : 24,
           "salary":NumberDecimal("7889.09"),
           "lenght" :1.35
    };
    var user3 ={
            "username" : "王五",
            "country" : "japan",
            "address" : {
                    "aCode" : "411000",
                    "add" : "长沙"
            },
            "favorites" : {
                    "movies" : ["肉蒲团","一路向西","倩女幽魂"],
                    "cites" : ["东莞","深圳","东京"]
            },
            "age" : 22,
           "salary":NumberDecimal("6666.66"),
           "lenght" :1.85
    };
    var user4 =
    {
            "username" : "马六",
            "country" : "USA",
            "address" : {
                    "aCode" : "411000",
                    "add" : "长沙"
            },
            "favorites" : {
                    "movies" : ["蜘蛛侠","钢铁侠","蝙蝠侠"],
                    "cites" : ["青岛","东莞","上海"]
            },
            "age" : 20,
           "salary":NumberDecimal("6398.22"),
           "lenght" :1.77
    };
    
    var user5 =
    {
            "username" : "test",
            "country" : "UK",
            "address" : {
                    "aCode" : "411000",
                    "add" : "TEST"
            },
            "favorites" : {
                    "movies" : ["蜘蛛侠","钢铁侠","蝙蝠侠"],
                    "cites" : ["青岛","东莞","上海"]
            },
           "salary":NumberDecimal("1969.88")
    };
    
    db.users.insert(user1);
    db.users.insert(user2);
    db.users.insert(user3);
    db.users.insert(user4);
    db.users.insert(user5);
    

       4、创建实体bean

      其中,@Getter等注解来自lombok
    @ToString
    @Getter
    @Setter
    @Generated
    @Builder
    @Document(collection = "users")
    public class User {
    @Id
    private String id;
        //姓名
        @Field("username")
        private String username;
        //国籍
        private String country;
        //年龄
        private int age;
        //薪水
        private BigDecimal salary;
        //身高
        private Double length;
        //地址
        private Address address;
        //爱好
        private HashMap favourites;
    }
    

      5、创建service

    @Service
    public class MongoTestService {
        @Autowired
        private MongoTemplate mongoTemplate;
        //查询
        public User getUserByName(String name){
            Query query = new Query();
            query.addCriteria(Criteria.where("username").is(name));
            User user = mongoTemplate.findOne(query, User.class);
            return user;
        }
    
        //插入
        public void insertUser(){
            HashMap map = new HashMap();
            map.put("movies", Arrays.asList("决战天门","倩女幽魂"));
            map.put("cities", Arrays.asList("大理","拉萨"));
            User user = User.builder()
                    .username("luochengwu")
                    .age(20)
                    .country("china")
                    .address(new Address("01002",""))
                    .favourites(map)
                    .salary(new BigDecimal("2345.67"))
                    .build();
            mongoTemplate.save(user);
        }
    
        //更新
        public void updateUser(){
            //把李四年龄修改为30
            Query query1 = new Query();
            query1.addCriteria(Criteria.where("username").is("李四"));
            List<User> lisi1 = mongoTemplate.find(query1,User.class);
            System.out.println("before update --------"+lisi1.get(0).toString());
            Update update1 = new Update();
            update1.set("age",30);
            UpdateResult result =mongoTemplate.updateMulti(query1,update1,User.class);
            List<User> lisi11 = mongoTemplate.find(query1,User.class);
            System.out.println("after update --------"+result);
            System.out.println("after user --------"+lisi11.get(0));
    
            //略复杂的条件
            //住在横滨的日本人,喜欢的城市添加东京
            Query query2 = new Query();
            query2.addCriteria(Criteria.where("country").is("japan").and("address.add").is("横滨"));
            User user1 = mongoTemplate.findOne(query2,User.class);
            System.out.println("before update ------"+user1);
            Update update2 = new Update();
            update2.addToSet("favourites.cities","东京");
            UpdateResult result2 = mongoTemplate.updateMulti(query2,update2,User.class);
            User user2 = mongoTemplate.findOne(query2,User.class);
            System.out.println("after update --------"+result2);
            System.out.println("after user --------"+user2);
        }
    
        //删除
        public void deleteUser(){
            //删掉国籍为uk,且年龄为22的人
            Query query = new Query();
            query.addCriteria(Criteria.where("country").is("UK").and("age").is(22));
            User user = mongoTemplate.findOne(query,User.class);
            System.out.println("待删除的用户 ------" + user);
            DeleteResult result = mongoTemplate.remove(query,User.class);
            System.out.println("remove response ------"+ result);
            User delUser = mongoTemplate.findOne(query,User.class);
            System.out.println("query after delete ------" + delUser);
        }
    }

      所碰到的问题:
      1、java跟mongodb数据类型转换的问题,一般java的数据类型跟数据库(比如mysql)的数据类型对应关系,数据库驱动已经帮我们做好了,那个“方言”的配置就是。mongodb貌似做的不全,有些是需要我们自己进行配置的,比如本例中的BigDecimal跟Decimal128;
      默认报错:
      解决办法:添加converter
    @Configuration
    public class MongodbConfig extends AbstractMongoConfiguration {
        @Value("${spring.data.mongodb.uri}")
        private String dburi ;
        @Override
        public MongoClient mongoClient() {
            MongoClient mongoClient = new MongoClient();
            return mongoClient;
        }
        @Override
        protected String getDatabaseName() {
            int index = dburi.lastIndexOf("/")+1;
            return dburi.substring(index);
        }
        @Bean
        public MappingMongoConverter mappingMongoConverter(){
            DefaultDbRefResolver dbRefResolver = new DefaultDbRefResolver(this.mongoDbFactory());
            MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, this.mongoMappingContext());
            List<Object> list = new ArrayList<>();
            list.add(new BigDecimalToDecimal128Converter());
            list.add(new Decimal128ToBigDecimal());
            converter.setCustomConversions(new MongoCustomConversions(list));
            return converter;
        }
        @Bean
        public MongoMappingContext mongoMappingContext(){
            MongoMappingContext mappingContext = new MongoMappingContext();
            return mappingContext;
        }
        @Bean
        public MongoTemplate mongoTemplate(){
            return new MongoTemplate(this.mongoDbFactory(),this.mappingMongoConverter());
        }
    }
    

      2、map跟hashmap的问题,被更新字段的数据类型必须明确。写Map报错:

      解决办法,将相关字段改为实现类HashMap,而不是用接口;这个当时困扰了一下,开始的时候没看懂这个异常;
      3、double跟Double的问题,由于mongodb数据结构的自由,有些记录可能缺少某些字段,也就是字段值为null,如果该字段为引用类型是没有问题的,但若该字段为int,double等基本数据类型时,会发生类型转换错误;
      解决办法,将字段改为包装类;so,pojo的各个属性最好为引用类型而不是简单类型,在使用关系数据库的时候也应该如此,有些字段(比如年龄,分数,价钱等),没填写跟值为0显然是两个概念。
    3、mongodb自带的原生api增删改查
    public class DocumentTest {
        private Logger log = LoggerFactory.getLogger(DocumentTest.class);
        private MongoDatabase db;
        private MongoCollection<Document> collection;
        private MongoClient client;
    
        @Before
        public void init(){
            client = new MongoClient("localhost");
            db = client.getDatabase("wzy");
            collection = db.getCollection("users");
        }
    
        //新增
        @Test
        public void insertTest(){
            Document doc1 = new Document();
            doc1.append("username","cang");
            doc1.append("age",20);
            doc1.append("country","japan");
            doc1.append("length",1.77f);
            doc1.append("salary",new BigDecimal("6565.22"));
    
            //对象
            Map<String,String> address = new HashMap<>();
            address.put("aCode","01001");
            address.put("add","大板");
            doc1.append("address",address);
    
            //数组
            Map<String,Object> fav = new HashMap<>();
            fav.put("movies", Arrays.asList("大决战","天龙"));
            fav.put("citys", Arrays.asList("杭州","苏州"));
            doc1.append("favourites",fav);
    
            collection.insertOne(doc1);
    //        collection.insertMany();
        }
    
        //查询
        @Test
        public void queryTest(){//{"favourites.cites":["长沙","上海"]}
            List<Document> list = new ArrayList<>();
            //mongo查询结果遍历接口
            Block<Document> block = new Block<Document>() {
                @Override
                public void apply(Document document) {
                    log.info(document.toJson());
                    list.add(document);
                }
            };
            FindIterable<Document> find1 = collection.find(all("favourites.cites",Arrays.asList("长沙","上海")));
            find1.forEach(block);
            log.info("结果有{}条", list.size());
    
            list.removeAll(list);
            //like '%s%',需要正则,  like '%s%' and (country = 'English' or country='USA')
            String regexStr = ".*s.*"; //s前后都可以有任意字符
            Bson regex = regex("username",regexStr);
            Bson or = or(eq("country","English"),eq("country","USA"));
            FindIterable<Document> find2 = collection.find(and(regex,or));
            find2.forEach(block);
            log.info("查询结果有{}条",list.size());
    
        }
    
        //更新
        @Test
        public void updateTest(){
            //更新单个字段
            UpdateResult result = collection.updateMany(eq("username","cang"),new Document("$set",new Document("age",6)));
            //替换整个文档
    //        UpdateResult result = collection.updateMany(eq("username","cang"),new Document(new Document("age",6)));
    
            UpdateResult result1 = collection.updateMany(eq("favourites.citys","杭州"),
                    addEachToSet("favourites.movies",Arrays.asList("小电影")));
    
            log.info("更新了{}条",result1.getModifiedCount());
        }
    
        //删除
        @Test
        public void deleteTest(){
            DeleteResult result = collection.deleteMany(Filters.eq("username","luochengwu"));
            log.info("删除了{}行",result.getDeletedCount());
            DeleteResult result1 = collection.deleteMany(and(gt("age",8),lt("age",28)));
            log.info("删除了{}行",result1.getDeletedCount());
        }
    }
    
      问题:经过前边对数据类型的趟坑,这里倒是没遇到什么异常;该部分最大的问题是对mongodb提供的原生api的不熟悉,尤其多个条件如何组合,and,or,exist的如何表达,文档整体更新跟局部更新如何处理等,这个感觉没什么办法,只能多多使用慢慢熟悉了;
    4、mongodb连接池
      mongodb团队已经帮我们做好了一个连接池,以供我们直接使用。使用方式也很简单,就是在获取client的时候将连接池参数对象传进去即可。
      连接池参数的设置是通过构造器模式来实现的,因为参数实在是比较多,我们可以根据自己需要进行自由设置。比如在第3步的单元测试类中,我们可以这样使用连接池:
    @Before
    public void init(){
        MongoClientOptions mco = MongoClientOptions.builder()
                .writeConcern(WriteConcern.ACKNOWLEDGED)
                .minConnectionsPerHost(100)
                .threadsAllowedToBlockForConnectionMultiplier(5)
                .maxWaitTime(120000)
                .connectTimeout(10000)
                .build();
        client = new MongoClient(new ServerAddress("localhost",27017), mco);
        db = client.getDatabase("wzy");
        collection = db.getCollection("users");
    }
    
    -------------------------------------------------------------------------------------------------
      以上,我们练习了spring template跟mongo原生api两种操作mongodb的方式。使用起来,要跟sql一样有查询条件,有and,or,like等,但显然,其语法跟细节跟sql是完全不想关的,精通sql跟熟练使用mongodb没有半毛钱关系。实际上,mongodb是有挺多细节需要注意的,我们稍后将在典型场景中进行详述。
     

     

  • 相关阅读:
    操盘策略:判断强庄股的四个诀窍
    三类股有望继续走强
    操盘策略:股市空头陷阱五大招数
    每日一招:面对亏损我们应该如何操作(鳄鱼法则)
    (转)一个大户的自白:我是这样被两融打爆的
    3.2、迭代
    3.1、切片
    2.4、递归函数
    2.3、函数的参数
    2.2、定义函数
  • 原文地址:https://www.cnblogs.com/nevermorewang/p/11486323.html
Copyright © 2020-2023  润新知