MongoDBJava异步驱动快速指南
执行异步回调
创建一个连接
MongoClient
获得一个collection
添加一个document
添加多个document
统计一个collection的document数量
查询collection
在一个collection中找到第一个document
遍历查找一个collection中所有的document
通过查询条件获得一个document
通过查询获得一组documents
document排序
投射域
聚合
更新document
删除document
批量操作
回到顶部
导读
mongodb-java-driver是mongodb的Java驱动项目。
本文是对MongoDB-java-driver官方文档MongoDBAsyncDriverQuickTour的翻译(原创翻译)。
mongodb-java-driver从3.0版本开始同时支持同步、异步方式(分别是不同的驱动应用)。异步的好处,众所周知,就是支持快速、非阻塞式的IO操作,可以提高处理速度。
请注意:本文仅介绍异步驱动的使用指南。同步驱动官方文档:mongo-java-driver,需要了解的朋友,请移驾。
回到顶部
安装
简单提下安装说明。
注:MongoDB异步驱动需要依赖Netty或Java7。
如果你的项目是maven项目,只需在pom.xml中添加如下依赖:
org.mongodb
mongodb-driver-async
3.3.0
你也可以点击链接直接下载jar包:下载点这里。
分割线,下面是MongoDBAsyncDriverQuickTour的译文。
回到顶部
MongoDB异步驱动快速指南
以下的代码片段来自于asyncdriversource的范例代码QuickTour.java。
注意
如何安装MongoDB异步驱动请参考安装指导。
执行异步回调
MongoDB异步驱动利用Netty或Java7的AsynchronousSocketChannel来提供一个支持异步的API,以支持快速的、非阻塞式的IO操作。
该API形式和MongoDB同步驱动的新API保持一致,但是任何会导致网络IO的方法都会有一个SingleResponseCallback并且会立即返回,其中T是响应对于该文档的类型的任何方法。
SingleResponseCallback回调接口需要实现一个简单方法onResult(Tresult,Throwablet),这个方法在操作完成时被调用。其中,如果操作成功,result参数包含着操作结果;如果操作失败,t中包含着抛出的异常信息。
重要
在SingleResponseCallback的实现中检查错误并适当处理错误是十分重要的。下面的错误检查仅为简便起见而省略。
创建一个连接
下面的例子展示多种方法去链接本地机器上的mydb数据库。详情参考MongoClients.createAPI手册。
//直接连接默认服务host和端口,即localhost:27017
MongoClientmongoClient=MongoClients.create();
//使用一个字符串
MongoClientmongoClient=MongoClients.create("mongodb://localhost");
//使用一个ConnectionString
MongoClientmongoClient=MongoClients.create(newConnectionString("mongodb://localhost"));
//使用MongoClientSettings
ClusterSettingsclusterSettings=ClusterSettings.builder().hosts(asList(newServerAddress("localhost"))).build();
MongoClientSettingssettings=MongoClientSettings.builder().clusterSettings(clusterSettings).build();
MongoClientmongoClient=Mongowww.wang027.comClients.create(settings);
MongoDatabasedatabase=mongoClient.getDatabase("mydb");
此时,database对象是一个MongoDB服务器中指定数据库的连接。
注意
getDatabase("mydb")方法并没有回调,因为它没有涉及网络IO操作。一个MongoDatabase实例提供了与数据库进行交互的方法,若数据库不存在,它会在插入数据时创建一个新的数据库。例如,创建一个collection或插入document(这些确实需要回调,因为需要涉及网络IO)。
MongoClient
MongoClient实例实际上代表了一个数据库的连接池;即使要并发执行异步操作,你也仅仅需要一个MongoClient实例。
重要
一般情况下,在一个指定的数据库集群中仅需要创建一个MongoClient实例,并通过你的应用使用它。
当创建多个实例时:
所有的资源使用限制(例如最大连接数)适用于每个MongoClient实例
销毁实例时,请确保调用MongoClient.close()清理资源。
获得一个collection
要获得一个collection,你需要在getCollection(StringcollectionName)方法中指定collection的名字:
下面的例子获得名为test的collection:
MongoCollectioncollection=database.getCollection("test");
添加一个document
一旦你有了collection对象,你就可以向collection中插入document。例如,考虑如下的json形式document;document中含包含了一个名为info的子document。
{
"name":"MongoDB",
"type":"database",
"count":1,
"info":{
x:203,
y:102
}
}
要创建document,需要使用Document类。你可以使用这个类来创建嵌入式的document。
Documentdoc=newDocument("name","MongoDB")
.append("type","database")
.append("count",1)
.append("info",newDocument("x",203).append("y",102));
要向collection中插入document,需要使用insertOne()方法。
collection.insertOne(doc,newSingleResultCallback(){
@Override
publicvoidonResult(finalVoidresult,finalThrowablet){
System.out.println("Inserted!");
}
});
SingleResponseCallback是一个函数式接口并且它可以以lambda方式实现(前提是你的APP工作在JDK8):
collection.insertOne(doc,(Voidresult,finalThrowablet)->System.out.println("Inserted!"));
一旦document成功插入,onResult回调方法会被调用并打印“Inserted!”。记住,在一个普通应用中,你应该总是检查t变量中是否有错误信息。
添加多个document
要添加多个documents,你可以使用insertMany()方法。
接下来的例子会添多个document,document形式如下:
{"i":value}
循环创建多个documents。
Listdocuments=newArrayList();
for(inti=0;i<100;i++){
documents.add(newDocument("i",i));
}
要插入多个document到collection,传递documents列表到insertMany()方法.
collection.insertMany(documents,newSingleResultCallback(){
@Override
publicvoidonResult(finalVoidresult,finalThrowablet){
System.out.println("Documentsinserted!");
}
});
统计一个collection的document数量
既然前面的多个例子中我们已经插入了101个document,我们可以检查一下插入数量,使用count()方法。下面的代码应该打印101。
collection.count(
newSingleResultCallback(){
@Override
publicvoidonResult(finalLongcount,finalThrowablet){
System.out.println(count);
}
});
查询collection
使用find()方法来查询collection。
在一个collection中找到第一个document
要获得collection中的第一个document,需要调用first()方法。collection.find().first()返回第一个document或null值,而不是一个游标。这种查询适用于匹配一个单一的document,,或你仅对第一个document有兴趣。
注意
有时你需要多次使用相同或相似的回调方法。在这种情况下,合理的做法是DRY(不要重复自己):把回调保存为一个具体的类或分配给一个变量。
SingleResultCallbackprintDocument=newSingleResultCallback(){
@Override
publicvoidonResult(finalDocumentdocument,finalThrowablet){
System.out.println(document.toJson());
}
};
下面的例子传递printDocument回调给first方法:
collection.find().first(printDocument);
范例会打印下面的document:
{"_id":{"$oid":"551582c558c7b4fbacf16735"},
"name":"MongoDB","type":"database","count":1,
"info":{"x":203,"y":102}}
注意
_id元素会被MongoDB动态的添加到你的document上,并且值也会与展示的不同。“_”和“$”开头的域是MongoDB预留给内部使用的。
遍历查找一个collection中所有的document
要检索collection中所有的document,需要使用find()方法。find()方法返回一个FindIterable实例,它提供了一个接口来链接和控制查找操作。使用forEach()方法可以提供一个Block作用于每个document并且迭代结束时执行回调一次。下面的代码遍历collection中所有的document并逐一打印,最后打印“OperationFinished!”。
BlockprintDocumentBlock=newBlock(){
@Override
publicvoidapply(finalDocumentdocument){
System.out.println(document.toJson());
}
};
SingleResultCallbackcallbackWhenFinished=newSingleResultCallback(){
@Override
publicvoidonResult(finalVoidresult,finalThrowablet){
System.out.println("OperationFinished!");
}
};
collection.find().forEach(printDocumentBlock,callbackWhenFinished);
通过查询条件获得一个document
我们可以创建一个过滤器传递给find()方法,以获得我们collection中的一组子集。例如,如果我们想查找key为“i”,value为71的document,我们要按下面的方法做(重用printDocument回调)。
importstaticcom.mongodb.client.model.Filters.;
collection.find(eq("i",71)).first(printDocument);
最终会只印一个document:
{"_id":{"$oid":"5515836e58c7b4fbc756320b"},"i":71}
重要
请使用Filters、Sorts、Projections和UpdatesAPI手册来找到简单、清晰的方法构建查询。
通过查询获得一组documents
我们可以使用查询来从我们的collection中获得一组document集合。例如,如果我们想获得所有key为“i”,value大于50的document,我们应该按下面方式做(重用printDocumentBlock阻塞和callbackWhenFinished回调):
//使用范围查询获取子集
collection.find(gt("i",50)).forEach(printDocumentBlock,callbackWhenFinished);
范例应该会打印所有i>50的document。
我们也可以增加上限范围,如50
collection.find(and(gt("i",50),lte("i",100))).forEach(printDocumentBlock,callbackWhenFinished);
document排序
我们可以对document进行排序。通过在FindIterable上调用sort()方法,我们可以在一个查询上进行一次排序。
下面的例子中,我们使用exists()和降序排序descending("i")来为我们的document排序。
collection.find(exists("i")).sort(descending("i")).first(printDocument);
投射域
有时我们不需要将所有的数据都存在一个document中。Projections可以用来为查询操作构建投射参数并限制返回的字段。
下面的例子中,我们会对collection进行排序,排除_id字段,并输出第一个匹配的document。
collection.find().projection(excludeId()).first(printDocument);
聚合
有时,我们需要将存储在MongoDB中的数据聚合。Aggregates支持对每种类型的聚合阶段进行构建。
下面的例子,我们执行一个两步骤的转换来计算i10的值。首先我们使用Aggregates.match查找所有i>0的document。接着,我们使用Aggregates.project结合$multiply操作来计算“ITimes10”的值。
collection.aggregate(asList(
match(gt("i",0)),
project(Document.parse("{ITimes10:{$multiply:[''$i'',10]}}")))
).forEach(printDocumentBlock,callbackwww.baiyuewang.netWhenFinished);
For$groupoperationsusetheAccumulatorshelperforanyaccumulatoroperations.
对于$group操作使用Accumulators来处理任何累加操作。
下面的例子中,我们使用Aggregates.group结合Accumulators.sum来累加所有i的和。
collection.aggregate(singletonList(group(null,sum("total","$i")))).first(printDocument);
注意
当前,还没有专门用于聚合表达式的工具类。可以使用Document.parse()来快速构建来自于JSON的聚合表达式。
更新document
MongoDB支持许多的更新操作。
要更新至多一个document(可能没有匹配的document),使用updateOne方法指定过滤器并更新document。这里,我们使用Updates.set来更新匹配过滤器i等于10的第一个document并设置i的值为110。
collection.updateOne(eq("i",10),set("i",110),
newSingleResultCallback(){
@Override
publicvoidonResult(finalUpdateResultresult,finalThrowablet){
System.out.println(result.getModifiedCount());
}
});
使用updateMany方法可以更新所有匹配过滤器的document。这里我们使用Updates.inc来为所有i小于100的document增加100。
collection.updateMany(lt("i",100),inc("i",100),
newSingleResultCallback(){
@Override
publicvoidonResult(finalUpdateResultresult,finalThrowablet){
System.out.println(result.getModifiedCount());
}
});
更新方法返回一个UpdateResult,其中包含了操作的信息(被修改的document的数量)。
删除document
要删除至多一个document(可能没有匹配的document)可以使用deleteOne方法。
collection.deleteOne(eq("i",110),newSingleResultCallback(){
@Override
publicvoidonResult(finalDeleteResultresult,finalThrowablet){
System.out.println(result.getDeletedCount());
}
});
使用deleteMany方法可以删除所有匹配过滤器的document。这里我们删除所有i大于等于的document。
collection.deleteMany(gte("i",100),newSingleResultCallback(){
@Override
publicvoidonResult(finalDeleteResultresult,finalThrowablet){
System.out.println(result.getDeletedCount());
}
});
删除方法返回一个DeleteResult,其中包含了操作的信息(被删除的document的数量)。
批量操作
批量操作允许批量的执行插入、更新、删除操作。批量操作有两种类型:
有序的批量操作
有序的执行所有操作并在第一个写操作的错误处报告错误。
无序的批量操作
执行所有的操作并报告任何错误。
无序的批量操作不保证执行顺序。
我们来围观一下两个分别使用有序和无序操作的简单例子:
SingleResultCallbackprintBatchResult=newSingleResultCallback(){
@Override
publicvoidonResult(finalBulkWriteResultresult,finalThrowablet){
System.out.println(result);
}
};
//2.有序批量操作
collection.bulkWrite(
Arrays.asList(newInsertOneModel<>(newDocument("_id",4)),
newInsertOneModel<>(newDocument("_id",5)),
newInsertOneModel<>(newDocument("_id",6)),
newUpdateOneModel<>(newDocument("_id",1),
newDocument("$set",newDocument("x",2))),
newDeleteOneModel<>(newDocument("_id",2)),
newReplaceOneModel<>(newDocument("_id",3),
newDocument("_id",3).append("x",4))),
printBatchResult
);
//2.无序批量操作
collection.bulkWrite(
Arrays.asList(newInsertOneModel<>(newDocument("_id",4)),
newInsertOneModel<>(newDocument("_id",5)),
newInsertOneModel<>(newDocument("_id",6)),
newUpdateOneModel<>(newDocument("_id",1),
newDocument("$set",newDocument("x",2))),
newDeleteOneModel<>(newDocument("_id",2)),
newReplaceOneModel<>(newDocument("_id",3),
newDocument("_id",3).append("x",4))),
newBulkWriteOptions().ordered(false),
printBatchResult
);
重要
不推荐在pre-2.6的MongoDB服务器上使用bulkWrite方法。因为这是第一个支持批量写操作(插入、更新、删除)的服务器版本,它允许驱动去实现BulkWriteResult和BulkWriteException的语义。这个方法虽然仍然可以在pre-2.6服务器上工作,但是性能不好,一次只能执行一个写操作。
|
|