监控变化

您可以通过打开更改流来跟踪 MongoDB 中数据的更改,例如对集合、数据库或部署的更改更改流允许应用程序监视数据更改并对其做出反应。更改流在发生更改时返回更改事件文档。您可以通过调用打开一个改变流watch()上的方法MongoCollectionMongoDatabaseMongoClient对象:

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实例,您可以使用遍历结果。

你可以调用的方法,MongoCursorhasNext()检查附加结果是否存在,next()以返回集合中的下一个文档,或者tryNext(),立即返回或者下一个可用的改变流中或元素nullMongoCursor其他查询返回的不同 MongoCursor与更改流相关联的 a 等待直到更改事件到达,然后才从 返回结果next()因此,调用next() 使用更改流MongoCursor永远不会抛出 java.util.NoSuchElementException.

要配置用于处理从更改流返回的文档的选项,请使用ChangeStreamIterable由 返回对象的成员方法watch()有关ChangeStreamIterable可用方法的更多详细信息,请参阅此示例底部API 文档链接

要从更改流中捕获事件,请forEach()使用回调函数调用该方法,如下所示:

changeStream.forEach(event -> System.out.println("Change observed: " + event));

 

回调函数在发出更改事件时触发。您可以在回调中指定逻辑以在接收到事件文档时对其进行处理。

重要的
forEach() 阻塞当前线程

forEach()只要相应的更改流侦听事件,就调用阻塞当前线程。如果您的程序需要继续执行其他逻辑,例如处理请求或响应用户输入,请考虑在单独的线程中创建和侦听更改流。

笔记

对于更新操作的变更事件,变更流默认只返回修改后的字段,而不是整个更新的文档。您可以将更改流配置为通过调用 具有如下fullDocument()ChangeStreamIterable对象成员方法来返回文档的最新版本FullDocument.UPDATE_LOOKUP

ChangeStreamIterable<Document> changeStream = database.watch().fullDocument(FullDocument.UPDATE_LOOKUP);

 

以下示例使用两个单独的应用程序来演示如何使用更改流侦听更改:

  • 第一个名为 的应用程序数据库中Watchmovies集合上打开更改流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类似以下应用程序的输出只 打印insertupdate操作,因为聚合管道过滤掉了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

如果您使用的是旧 API, 请参阅我们的常见问题解答页面 以了解您需要对此代码示例进行哪些更改。

 

官网文档:https://docs.mongodb.com/drivers/java/sync/current/usage-examples/watch/