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

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里面的……

    原文作者:lazyguy
    原文地址: https://www.jianshu.com/p/d4bc20e9ae2f
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞