监控变化
您可以通过打开更改流来跟踪 MongoDB 中数据的更改,例如对集合、数据库或部署的更改。更改流允许应用程序监视数据更改并对其做出反应。更改流在发生更改时返回更改事件文档。您可以通过调用打开一个改变流watch()
上的方法MongoCollection
,MongoDatabase
或MongoClient
对象:
ChangeStreamIterable<Document> changeStream = database.watch();
该watch()
方法可选地采用 由阶段数组组成的聚合管道作为第一个参数来过滤和转换更改事件输出,如下所示:
List<Bson> pipeline = Arrays.asList( Aggregates.match( Filters.lt("fullDocument.runtime", 15))); ChangeStreamIterable<Document> changeStream = database.watch(pipeline);
该watch()
方法返回 的实例ChangeStreamIterable
,该类提供多种方法来访问、组织和遍历结果。 ChangeStreamIterable
还从其父类继承方法,该类 MongoIterable
实现了核心 Java 接口Iterable
。
您可以拨打forEach()
在ChangeStreamIterable
处理事件发生时,也可以使用iterator()
它返回一个方法MongoCursor
实例,您可以使用遍历结果。
你可以调用的方法,MongoCursor
如hasNext()
检查附加结果是否存在,next()
以返回集合中的下一个文档,或者tryNext()
,立即返回或者下一个可用的改变流中或元素null
。与MongoCursor
其他查询返回的不同 ,MongoCursor
与更改流相关联的 a 等待直到更改事件到达,然后才从 返回结果next()
。因此,调用next()
使用更改流MongoCursor
永远不会抛出 java.util.NoSuchElementException
.
要配置用于处理从更改流返回的文档的选项,请使用ChangeStreamIterable
由 返回的对象的成员方法watch()
。有关ChangeStreamIterable
可用方法的更多详细信息,请参阅此示例底部的API 文档链接。
如何使用回调处理变更流事件
要从更改流中捕获事件,请forEach()
使用回调函数调用该方法,如下所示:
changeStream.forEach(event -> System.out.println("Change observed: " + event));
回调函数在发出更改事件时触发。您可以在回调中指定逻辑以在接收到事件文档时对其进行处理。
forEach()
只要相应的更改流侦听事件,就调用阻塞当前线程。如果您的程序需要继续执行其他逻辑,例如处理请求或响应用户输入,请考虑在单独的线程中创建和侦听更改流。
对于更新操作的变更事件,变更流默认只返回修改后的字段,而不是整个更新的文档。您可以将更改流配置为通过调用 具有如下值fullDocument()
的ChangeStreamIterable
对象的成员方法来返回文档的最新版本FullDocument.UPDATE_LOOKUP
:
ChangeStreamIterable<Document> changeStream = database.watch().fullDocument(FullDocument.UPDATE_LOOKUP);
示例
以下示例使用两个单独的应用程序来演示如何使用更改流侦听更改:
- 第一个名为 的应用程序在数据库中
Watch
的movies
集合上打开更改流sample_mflix
。Watch
使用聚合管道过滤更改,operationType
以便它只接收插入和更新事件(删除被遗漏排除)。Watch
使用回调来接收和打印集合上发生的过滤更改事件。 - 第二个名为 的应用程序
WatchCompanion
将单个文档插入到 数据库的movies
集合中sample_mflix
。接下来,WatchCompanion
使用新的字段值更新文档。最后,WatchCompanion
删除文档。
首先,运行Watch
以打开集合上的更改流,并使用forEach()
方法在更改流上定义回调。在Watch
运行时,运行WatchCompanion
以通过对集合执行更改来生成更改事件。
此示例使用连接字符串连接到 MongoDB 实例。要了解有关连接到 MongoDB 实例的更多信息,请参阅 连接指南。
Watch
:
package usage.examples;
import org.bson.Document; import org.bson.conversions.Bson; import com.mongodb.client.ChangeStreamIterable; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.mongodb.client.model.Filters; import com.mongodb.client.model.changestream.FullDocument;
public class Watch { public static void main( String[] args ) { // Replace the uri string with your MongoDB deployment's connection string String uri = "<connection string uri>"; try (MongoClient mongoClient = MongoClients.create(uri)) { MongoDatabase database = mongoClient.getDatabase("sample_mflix"); MongoCollection<Document> collection = database.getCollection("movies"); List<Bson> pipeline = Arrays.asList( Aggregates.match( Filters.in("operationType", Arrays.asList("insert", "update")))); ChangeStreamIterable<Document> changeStream = database.watch(pipeline) .fullDocument(FullDocument.UPDATE_LOOKUP); // variables referenced in a lambda must be final; final array gives us a mutable integer final int[] numberOfEvents = {0}; changeStream.forEach(event -> { System.out.println("Received a change to the collection: " + event); if (++numberOfEvents[0] >= 2) { System.exit(0); } }); } } }
WatchCompanion
:
package usage.examples;
import java.util.Arrays; import org.bson.Document; import org.bson.types.ObjectId; import com.mongodb.MongoException; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.mongodb.client.result.InsertOneResult;
public class WatchCompanion { public static void main(String[] args) { // Replace the uri string with your MongoDB deployment's connection string String uri = "<connection string uri>"; try (MongoClient mongoClient = MongoClients.create(uri)) { MongoDatabase database = mongoClient.getDatabase("sample_mflix"); MongoCollection<Document> collection = database.getCollection("movies"); try { InsertOneResult insertResult = collection.insertOne(new Document("test", "sample movie document")); System.out.println("Success! Inserted document id: " + insertResult.getInsertedId()); UpdateResult updateResult = collection.updateOne(new Document("test", "sample movie document"), Updates.set("field2", "sample movie document update")); System.out.println("Updated " + updateResult.getModifiedCount() + " document."); DeleteResult deleteResult = collection.deleteOne(new Document("field2", "sample movie document update")); System.out.println("Deleted " + deleteResult.getDeletedCount() + " document."); } catch (MongoException me) { System.err.println("Unable to insert, update, or replace due to an error: " + me); } } } }
如果您按顺序运行上述应用程序,您应该会看到Watch
类似以下应用程序的输出。只 打印insert
和update
操作,因为聚合管道过滤掉了delete
操作:
Received a change to the collection: ChangeStreamDocument{ operationType=OperationType{value='insert'}, resumeToken={"_data": "825EC..."}, namespace=sample_mflix.movies, destinationNamespace=null, fullDocument=Document{{_id=5ec3..., test=sample movie document}}, documentKey={"_id": {"$oid": "5ec3..."}}, clusterTime=Timestamp{...}, updateDescription=null, txnNumber=null, lsid=null } Received a change to the collection: ChangeStreamDocument{ operationType=OperationType{value='update'}, resumeToken={"_data": "825EC..."}, namespace=sample_mflix.movies, destinationNamespace=null, fullDocument=Document{{_id=5ec3..., test=sample movie document, field2=sample movie document update}}, documentKey={"_id": {"$oid": "5ec3..."}}, clusterTime=Timestamp{...}, updateDescription=UpdateDescription{removedFields=[], updatedFields={"field2": "sample movie document update"}}, txnNumber=null, lsid=null }
您还应该看到WatchCompanion
类似于以下内容的应用程序输出:
Success! Inserted document id: BsonObjectId{value=5ec3...} Updated 1 document. Deleted 1 document.
如果您使用的是旧 API, 请参阅我们的常见问题解答页面 以了解您需要对此代码示例进行哪些更改。
官网文档:https://docs.mongodb.com/drivers/java/sync/current/usage-examples/watch/