美文网首页Mongo 我爱编程
mongodb-java-driver做基本的CRUD--基本查

mongodb-java-driver做基本的CRUD--基本查

作者: lazyguy | 来源:发表于2018-01-11 16:05 被阅读167次

    title: mongodb-2 mongodb-java-driver做基本的CRUD--基本查询
    date: 2017-01-11 16:25:59
    tags:
    categories: mongodb


    本文demo代码地址:https://github.com/lazyguy21/mongoDemo

    如何连接mongodb?
    http://mongodb.github.io/mongo-java-driver/3.4/driver/tutorials/connect-to-mongodb/
    其中MongoClient类比jdbc时的连接池,全局唯一。MongoCollection类似于Connection
    不同的是,使用完MongoCollection后并不需要像JDBC,redis的jedis客户端一样手动返回,很方便。

    利用Document构建查询语句

    mongodb-java-driver为我们提供了2种方式。一种是用Document(类似Map)来构建一个JSON式的对象。怎么个搞法呢?

    @Test
    public void testQuery() throws Exception {
        Document document = new Document("price", new Document("$gte", 1)
                .append("$lt", 500))
                .append("name", "shirt");
        System.out.println(document.toJson());
        MongoCollection<Document> clothCollection = mongoClient.getDatabase("test").getCollection("Cloth");
        FindIterable<Document> results = clothCollection.find(document);
        results.forEach((Consumer<? super Document>) System.out::println);
    }
    

    说实话用json(或者说BSON)的样式作为交互语言,给习惯了sql的我来说本来就十分别扭了,翻译成这个样子之后,不管你怎么看,我觉得简直是崩溃。研究了很久之后,我发现Document提供了2个便利方法。

    一个是Document.parse将一个JSON字符串反序列化为Document,

    一个是toJson可以把Document序列化为json字符串。

    这样tojson方法可以作为一种查看你最后写的BSON语句正确与否的手段。如果记录在日志里面,就可以像打印sql一样留下记录了!

    /**
     * 使用mongodb时怎么去判断自己最后写出的语句对不对呢?
     *
     * @throws Exception
     */
    @Test
    public void testToJson() throws Exception {
        Document document = new Document("price", new Document("$gte", 1)
                .append("$lt", 5))
                .append("name", "shirt");
        String string = document.toJson();
        String s = document.toString();
        System.out.println( s);
        System.out.println(string);
    
    }
    

    输出:

    Document{{price=Document{{$gte=1, $lt=5}}, name=shirt}}
    { "price" : { "$gte" : 1, "$lt" : 5 }, "name" : "shirt" }
    

    前者是toString,后者是toJson的结果。可以看见tojson可以直接复制到GUI里面调试。

    使用Filters工具类简写

     @Test
        public void testQuery2() throws Exception {
            MongoCollection<Document> clothCollection = mongoClient.getDatabase("test").getCollection("Cloth");
    //        此Document等于下面的简写
    //        new Document("stars", new Document("$gte", 2)
    //                .append("$lt", 5))
    //                .append("categories", "Bakery")
            clothCollection.find(and(gte("stars", 2), lt("stars", 5), eq("categories", "Bakery")))
                    .forEach((Consumer<? super Document>) System.out::println);
    
        }
    

    很容易理解的工具类,不过这样写无法利用toJson方法,因为生成的不是Document。

    限制Document返回的Field

    @Test
    public void testKey() throws Exception {
        FindIterable<Document> results = clothCollection.find().projection(Projections.include("name"));
        results.forEach((Consumer<? super Document>) System.out::println);
    }
    

    输出:

    Document{{_id=586f4c462148d00ffe8d9787, name=shirt}}
    

    如上,返回的仅仅只有_id 和name。

    这段实际在shell中就是:db.Cloth.find(null,{"name":1}); 1表示include,0表示exclude,其中_id在没有指明的时候默认回传。

    通过主键查询ID

    @Test
        public void queryDate() throws Exception {
    //        FindIterable<Document> results = clothCollection.find(Filters.eq("_id", "58759260bc497244060ba7c0"));
            FindIterable<Document> results = clothCollection.find(new Document("_id", new ObjectId("58759260bc497244060ba7c0")));
            
            results.forEach((Consumer<? super Document>) document -> {
                System.out.println(document);
            });
    
        }
    

    注意Mongodb的主键类型是ObjectID,需要自己去构造。

    分页

    @Test
    public void testPagination() throws Exception {
        int pageNum=1;
        int pageSize=3;
        FindIterable<Document> results = clothCollection.find().skip((pageNum-1)*pageSize).limit(pageSize);
        long count = clothCollection.count();
        System.out.println("count :"+count);
        results.forEach((Consumer<? super Document>) document -> {
            System.out.println(document);
        });
    
    }
    

    mongodb的分skip和count都是非常耗时的操作,数据量达到几百万的时候,最好别进行count。

    分页最好只显示前面几十页即可。

    或者使用上一页的id作为条件,排序查询代替分页(这样做的弊端是翻页的时候不能跳页,好处是可以一直翻下去,而且不会变慢,其实感觉这样的需求并不强)。

    所以一般常见的做法就是别count,分页只拿前面部分。

    OR 或查询

    @Test
        public void testOR() throws Exception {
    //        Document document = new Document("$or", new Object[]{new Document("label", "adfad"), new Document("name", "T")});
    //        Document[] documentsParam = new Document[]{new Document("label", "adfad"), new Document("name", "T")};
            ArrayList<Document> documentsParam = Lists.newArrayList(new Document("label", "adfad"), new Document("name", "T"));
            Document document = new Document("$or", documentsParam);
            FindIterable<Document> documents = clothCollection.find(document);
            documents.forEach((Consumer<? super Document>) document1 -> {
                System.out.println(document1);
            });
    
        }
    

    上面的代码查询的是name=T或者label=adfad的文档。

    shell就是:find({ "$or" : [{ "label" : "adfad" }, { "name" : "T" }] })

    值得一提的是驱动能认识ArrayList,却没有Array的解析器……

    IN查询

    @Test
    public void testIN() throws Exception {
        Bson queryParam = Filters.in("name", "T", "shirt");
        FindIterable<Document> documents = clothCollection.find(queryParam);
        documents.forEach((Consumer<? super Document>) document1 -> System.out.println(document1));
    }
    

    in也可以在单filed的时候或
    shell :find{"name",{"$in" : [ "shirt","T" ]}}

    上面代码用的Filters辅助类,参数既可以接受可变参数,也可以是List

    NULL查询

    @Test
    public void testNULL() throws Exception {
        FindIterable<Document> results = clothCollection.find(new Document("name", null));
        results.forEach((Consumer<? super Document>) document1 -> System.out.println(document1));
    }
    

    输出:

    Document{{_id=58735ed5bc49722dd7b74f91, name=null}}
    Document{{_id=58759260bc497244060ba7c0, date=Wed Jan 11 10:03:12 CST 2017}}
    

    可以看到单纯的传 name:null这样的条件,将会匹配到name的值本身为null的Document,也会匹配到根本就没有name这个field的Document!!

    匹配有name字段并且name字段值为null的Document

    @Test
    public void testNULL2() throws Exception {
        ArrayList<Object> objects = Lists.newArrayList();
        objects.add(null);
        FindIterable<Document> documents = clothCollection.find(Filters.and(Filters.in("name",objects), Filters.exists("name")));
        documents.forEach((Consumer<? super Document>) document1 -> System.out.println(document1));
    }
    

    shell即为:{name:{"$in":[null],"$exits":true}}

    没有$eq 这种操作符……只能用$in来代替

    比较尴尬的是,null对于java来说也是很特殊的字段,注意上面代码中,我是怎么传null到list里面的……

    相关文章

      网友评论

        本文标题:mongodb-java-driver做基本的CRUD--基本查

        本文链接:https://www.haomeiwen.com/subject/iuctoxtx.html