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