环境
MongoDB:3.0+
mongodb dirver for java: 3.4
@author:喻涛
概要
本篇是翻译官网:
https://mongodb.github.io/mongo-java-driver/3.4/driver/tutorials/perform-read-operations/
讲解的是用java
代码对MongoDB进行读操作。
Find Operations 查询操作
查询操作是从集合中检索文档。你可以指定过滤器,去选择只匹配过符合滤条件的文档。
先决条件
在test
数据库中要有一个restaurants
集合。
(你可以使用你本地的测试环境中的集合,来做下面的测试)
可能需要import
的声明:
import com.mongodb.*;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Projections;
import com.mongodb.client.model.Filters;
import static com.mongodb.client.model.Filters.*;
import static com.mongodb.client.model.Projections.*;
import com.mongodb.client.model.Sorts;
import java.util.Arrays;
import org.bson.Document;
下面的这段代码是在教程示例中将会打印查询操作的结果。
Block<Document> printBlock = new Block<Document>() {
@Override
public void apply(final Document document) {
System.out.println(document.toJson());
}
};
连接数据库
这里我贴出我自己的代码:
//连接数据库 start
MongoCredential credential =
//根据自己的情况修改
MongoCredential.createCredential("gg_openapi",
"gg_openapi", "gg..openapi#!".toCharArray());
//根据自己的情况修改
serverAddress = new ServerAddress("106.75.51.20", 35520);
List<ServerAddress> addrs = new ArrayList<ServerAddress>();
addrs.add(serverAddress);
List<MongoCredential> credentials = new ArrayList<MongoCredential>();
credentials.add(credential);
@SuppressWarnings("resource")
MongoClient mongoClient = new MongoClient(addrs, credentials);
MongoDatabase database = mongoClient.getDatabase("gg_openapi");
System.out.println("Connect to database successfully");
//连接数据库 end
对集合进行查询
对集合进行查询,你可以使用find()
方法。
你可以在集合中调用这个方法,不传参数就是查询全部的文档。
collection.find().forEach(printBlock);
或者传入一个过滤器来查询符合过滤标准的文档。
collection.find(eq("name", "456 Cookies Shop"))
.forEach(printBlock);
查询 过滤器
要查询符合特定条件的文档,可以给find()
方法,传入一个过滤器文档。
(可能看着很拗口,看看下面就明白啦)
空过滤器
要指定一个空过滤器(这样做的话,就是查询全部文档),使用空的Document
对象。
collection.find(new Document()).forEach(printBlock);
当然你也可以用更简单的写法:
collection.find().forEach(printBlock);
Filters 助手
为了方便的创建过滤器文档,java
驱动提供了Filters
类,这个类提供有很多过滤条件的方法。
假设现在我们有这样一些需求:
①字段stars
大于等于2并且小于5
②categories
字段等于Bakery
(如果categories
是个数组,那就是包含Bakery
)。
collection.find(
new Document("stars", new Document("$gte", 2)
.append("$lt", 5))
.append("categories", "Bakery")).forEach(printBlock);
以下示例是使用Filters
助手指定相同过滤条件:
collection.find(and(gte("stars", 2), lt("stars", 5), eq("categories", "Bakery"))).forEach(printBlock);
关于MongoDB
过滤查询列表,可以参考MongoDB Manual
,有关Filters
助手可以查看Filters
。
另请参考在MongoDB
查询概述中的Query Documents Tutorial
,包括在数组和嵌套文档中指定过滤条件。
FindIterable
find()
方法会返回FindIterable
接口的一个实例。这个接口提供了各种方法,你可以链接到find()
方法改变输出和查询的行为,例如:sort()
或projection()
,以及对结果的遍历,例如:iterator()
和forEach()
。
Projections
默认情况下,在MongoDB
查询匹配文档中返回全部字段。要在匹配的文档中返回指定字段,你需要指定projection document
下面的find
操作中包含一个projection
其要插入Document
对象,该对象是用来指定返回匹配的文档字段为:name
、stars
和categories
。
collection.find(and(gte("stars", 2),
lt("stars", 5),
eq("categories", "Bakery")))
.projection(new Document("name", 1)
.append("stars", 1)
.append("categories",1)
.append("_id", 0))
.forEach(printBlock);
为了方便创建projection
文档,java
驱动提供了Projections
类。
collection.find(and(gte("stars", 2),
lt("stars", 5),
eq("categories", "Bakery")))
.projection(fields(include("name", "stars",
"categories"),
excludeId()))
.forEach(printBlock);
在projection
文档(这里的文档你可以理解对Document对象)中,你也可以使用projection
操作符指定projection表达式。
有关使用Projections.metaTextScore
的示例,可以参考Text Search tutorial.
sorts
要排序文档,可以把排序规范的文档(这里的文档你可以理解对Document对象)传递给FindIterable.sort()
方法。
java驱动程序也提供了Sorts
助手来方便我们进行排序操作。
collection.find(and(gte("stars", 2),
lt("stars", 5),
eq("categories","Bakery")))
.sort(Sorts.ascending("name"))
.forEach(printBlock);
Sort with Projections
FindIterable方法本身就返回FindIterable
对象。因此,你可以应用多个FindIterable
方法在find()
方法中。
collection.find(and(gte("stars", 2),
lt("stars", 5),
eq("categories", "Bakery")))
.sort(Sorts.ascending("name"))
.projection(fields(include("name",
"stars",
"categories"),excludeId()))
.forEach(printBlock);
MongoIterable
MongoIterable提供了帮助方法来访问操作结果:
①iterator()
②first()
③forEach()
④map()
⑤into()
读取偏好 Read Preference
对于复制集和分片集群的读取操作,应用程序可以在三个层次中对read Preference
进行配置。
一、 In a MongoClient()
①通过MongoClientOptions
:
MongoClientOptions options = MongoClientOptions.builder()
.readPreference(ReadPreference.secondary())
.build();
MongoClient mongoClient = new MongoClient(Arrays.asList(
new ServerAddress("host1", 27017),
new ServerAddress("host2", 27017)), options);
②通过MongoClientURI
,如下所示:
MongoClient mongoClient = new MongoClient(
new MongoClientURI("mongodb://host1:27017,host2:27017/?readPreference=secondary"));
二、In a MongoDatabase
通过 withReadPreference
方法。
MongoDatabase database = mongoClient.getDatabase("test")
.withReadPreference(ReadPreference.secondary());
三、In a MongoCollection
通过withReadPreference
方法:
MongoCollection<Document> collection= database.getCollection("restaurants")
.withReadPreference(ReadPreference.secondary());
MongoDatabase
和MongoCollection
实例是不可变的。
在已存在的MongoDatabase
和MongoCollection
实例中调用withReadPreference()
方法会返回一个新的实例并不影响调用该方法的实例。
例如,下面代码,collectionWithReadPref
实例有个read preference
为primaryPreferred
而collection
的read preference
是不是影响的。
MongoCollection<Document> collectionWithReadPref =
collection.withReadPreference(ReadPreference.primaryPreferred());
//collection的read preference是不受影响的
Read Concern
对于复制集和分片集群的读取操作,应用程序可以在三个层次中对read concern
进行配置。
①通过MongoClientURI
,如下所示:
MongoClient mongoClient = new MongoClient(
new MongoClientURI("mongodb://host1:27017,host2:27017/?readConcernLevel=majority"));
②通过MongoClientOptions
,如下所示:
MongoClientOptions options = MongoClientOptions.builder().readConcern(ReadConcern.DEFAULT).build();
MongoClient mongoClient = new MongoClient(Arrays.asList(
new ServerAddress("host1", 27017),
new ServerAddress("host1", 27017)), options);
二、在MongoDatabase
中
通过withReadConcern
方法,如下所示:
MongoDatabase database = mongoClient.getDatabase("test")
.withReadConcern(ReadConcern.DEFAULT);
三、在MongoCollection
中
通过withReadConcern
方法,如下所示:
MongoCollection<Document> collection =
database.getCollection("restaurants").withReadConcern(ReadConcern.DEFAULT);
你可以构建MongoClientOptions
、MongoDatabase
或者MongoCollection
,来包含read concern
、read preference
和write concern
的组合。
例如:下面的集合中包含了上面全部的三种情况。
collection = database.getCollection("restaurants")
//read preference
.withReadPreference(ReadPreference.primary())
//read concern
.withReadConcern(ReadConcern.MAJORITY)
//write concern
.withWriteConcern(WriteConcern.MAJORITY);
总结
1、最后面的几种配置,我们平时用不到。
2、新的驱动提供了Filters
类,这样以后就可以不用写诸如下面这样的代码:
Document document = new Document();
document.append("categories", "Bakery");
虽然诸如:and
、gte
、lt
等这样的helper
方法可以使代码简洁;
但是我还是建议使用创建Document
的方法。因为它使用的是MongoDB
本身的操作符;
这样的好处,就是方便你不断强化记住MongoDB
原始的操作符;
这样你在MongoDB
客户端中写查询语句也不会很陌生。