diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index 25e7a1985..184b514b3 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -10,7 +10,7 @@ * <>. * <> for queries and collection creation. * <> for imperative and reactive drivers. -* Tailable cursors for imperative driver. +* <> for imperative driver. * <> support for the imperative and reactive Template APIs. * <> support and a MongoDB-specific transaction manager implementation. * <> using `@Query(sort=…)`. diff --git a/src/main/asciidoc/reference/mongodb.adoc b/src/main/asciidoc/reference/mongodb.adoc index a9440e28a..60a9f473b 100644 --- a/src/main/asciidoc/reference/mongodb.adoc +++ b/src/main/asciidoc/reference/mongodb.adoc @@ -165,7 +165,7 @@ There is a https://github.com/spring-projects/spring-data-examples[GitHub reposi [[mongodb-connectors]] == Connecting to MongoDB with Spring -One of the first tasks when using MongoDB and Spring is to create a `com.mongodb.MongoClient` object using the IoC container. There are two main ways to do this, either by using Java-based bean metadata or by using XML-based bean metadata. Both are discussed in the following sections. +One of the first tasks when using MongoDB and Spring is to create a `com.mongodb.MongoClient` or `com.mongodb.client.MongoClient` object using the IoC container. There are two main ways to do this, either by using Java-based bean metadata or by using XML-based bean metadata. Both are discussed in the following sections. NOTE: For those not familiar with how to configure the Spring container using Java-based bean metadata instead of XML-based metadata, see the high-level introduction in the reference docs http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/new-in-3.0.html#new-java-configuration[here] as well as the detailed documentation http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/core.html#beans-java-instantiating-container[here]. @@ -322,6 +322,8 @@ public class MongoApp { The code in bold highlights the use of `SimpleMongoDbFactory` and is the only difference between the listing shown in the <>. +NOTE: Use `SimpleMongoClientDbFactory` when choosing `com.mongodb.client.MongoClient` as the entrypoint of choice. + [[mongo.mongo-db-factory-java]] === Registering a `MongoDbFactory` Instance by Using Java-based Metadata @@ -363,9 +365,7 @@ In order to use authentication with XML-based configuration, use the `credential NOTE: Username and password credentials used in XML-based configuration must be URL-encoded when these contain reserved characters, such as `:`, `%`, `@`, or `,`. The following example shows encoded credentials: - `m0ng0@dmin:mo_res:bw6},Qsdxx@admin@database` -> `m0ng0%40dmin:mo_res%3Abw6%7D%2CQsdxx%40admin@database` - See https://tools.ietf.org/html/rfc3986#section-2.2[section 2.2 of RFC 3986] for further details. As of MongoDB java driver 3.7.0 there is an alternative entry point to `MongoClient` via the https://search.maven.org/beta/search?q=a:mongodb-driver-sync[mongodb-driver-sync] artifact. @@ -3085,4 +3085,5 @@ class GridFsClient { `GridFsOperations` extends `ResourcePatternResolver` and lets the `GridFsTemplate` (for example) to be plugged into an `ApplicationContext` to read Spring Config files from MongoDB database. +include::tailable-cursors.adoc[] include::change-streams.adoc[] diff --git a/src/main/asciidoc/reference/reactive-mongo-repositories.adoc b/src/main/asciidoc/reference/reactive-mongo-repositories.adoc index 76c7e7f9f..a8ab6dfed 100644 --- a/src/main/asciidoc/reference/reactive-mongo-repositories.adoc +++ b/src/main/asciidoc/reference/reactive-mongo-repositories.adoc @@ -198,53 +198,3 @@ public interface PersonRepository extends ReactiveMongoRepository> findByLocationNear(Point location); } ---- - -[[mongo.reactive.repositories.infinite-streams]] -== Infinite Streams with Tailable Cursors - -By default, MongoDB automatically closes a cursor when the client exhausts all results supplied by the cursor. Closing a cursor on exhaustion turns a stream into a finite stream. For https://docs.mongodb.com/manual/core/capped-collections/[capped collections], you can use a https://docs.mongodb.com/manual/core/tailable-cursors/[Tailable Cursor] that remains open after the client consumes all initially returned data. Using tailable cursors with a reactive data types allows construction of infinite streams. A tailable cursor remains open until it is closed externally. It emits data as new documents arrive in a capped collection. - -Tailable cursors may become dead, or invalid, if either the query returns no match or the cursor returns the document at the "`end`" of the collection and the application then deletes that document. The following example shows how to create and use an infinite stream query: - - -.Infinite Stream queries with ReactiveMongoOperations -==== -[source,java] ----- -Flux stream = template.tail(query(where("name").is("Joe")), Person.class); - -Disposable subscription = stream.doOnNext(person -> System.out.println(person)).subscribe(); - -// … - -// Later: Dispose the subscription to close the stream -subscription.dispose(); ----- -==== - -Spring Data MongoDB Reactive repositories support infinite streams by annotating a query method with `@Tailable`. This works for methods that return `Flux` and other reactive types capable of emitting multiple elements, as the following example shows: - -.Infinite Stream queries with ReactiveMongoRepository -==== -[source,java] ----- - -public interface PersonRepository extends ReactiveMongoRepository { - - @Tailable - Flux findByFirstname(String firstname); - -} - -Flux stream = repository.findByFirstname("Joe"); - -Disposable subscription = stream.doOnNext(System.out::println).subscribe(); - -// … - -// Later: Dispose the subscription to close the stream -subscription.dispose(); ----- -==== - -TIP: Capped collections can be created with `MongoOperations.createCollection`. To do so, provide the required `CollectionOptions.empty().capped()...`. diff --git a/src/main/asciidoc/reference/tailable-cursors.adoc b/src/main/asciidoc/reference/tailable-cursors.adoc new file mode 100644 index 000000000..b6233df90 --- /dev/null +++ b/src/main/asciidoc/reference/tailable-cursors.adoc @@ -0,0 +1,101 @@ +// carry over the old bookmarks to prevent external links from failing +[[tailable-cursors]] +== [[mongo.reactive.repositories.infinite-streams]] Infinite Streams with Tailable Cursors + +By default, MongoDB automatically closes a cursor when the client exhausts all results supplied by the cursor. +Closing a cursor on exhaustion turns a stream into a finite stream. For https://docs.mongodb.com/manual/core/capped-collections/[capped collections], +you can use a https://docs.mongodb.com/manual/core/tailable-cursors/[Tailable Cursor] that remains open after the client +consumed all initially returned data. + +TIP: Capped collections can be created with `MongoOperations.createCollection`. To do so, provide the required `CollectionOptions.empty().capped()...`. + +Tailable cursors can be consumed with both, the imperative and the reactive MongoDB API. It is highly recommended to use the +reactive variant, as it is less resource-intensive. However, if you cannot use the reactive API, you can still use a messaging +concept that is already prevalent in the Spring ecosystem. + +[[tailable-cursors.sync]] +=== Tailable Cursors with `MessageListener` + +Listening to a capped collection using a Sync Driver creates a long running, blocking task that needs to be delegated to +a separate component. In this case, we need to first create a `MessageListenerContainer`, which will be the main entry point +for running the specific `SubscriptionRequest`. Spring Data MongoDB already ships with a default implementation that +operates on `MongoTemplate` and is capable of creating and executing `Task` instances for a `TailableCursorRequest`. + +The following example shows how to use tailable cursors with `MessageListener` instances: + +.Tailable Cursors with `MessageListener` instances +==== +[source,java] +---- +MessageListenerContainer container = new DefaultMessageListenerContainer(template); +container.start(); <1> + +MessageListener listener = System.out::println; <2> + +TailableCursorRequest request = TailableCursorRequest.builder() + .collection("orders") <3> + .filter(query(where("value").lt(100))) <4> + .publishTo(listener) <5> + .build(); + +container.register(request, User.class); <6> + +// ... + +container.stop(); <7> +---- +<1> Starting the container intializes the resources and starts `Task` instances for already registered `SubscriptionRequest` instances. Requests added after startup are ran immediately. +<2> Define the listener called when a `Message` is received. The `Message#getBody()` is converted to the requested domain type. Use `Document` to receive raw results without conversion. +<3> Set the collection to listen to. +<4> Provide an optional filter for documents to receive. +<5> Set the message listener to publish incoming ``Message``s to. +<6> Register the request. The returned `Subscription` can be used to check the current `Task` state and cancel its execution to free resources. +<5> Do not forget to stop the container once you are sure you no longer need it. Doing so stops all running `Task` instances within the container. +==== + +[[tailable-cursors.reactive]] +=== Reactive Tailable Cursors + +Using tailable cursors with a reactive data types allows construction of infinite streams. A tailable cursor remains open until it is closed externally. It emits data as new documents arrive in a capped collection. + +Tailable cursors may become dead, or invalid, if either the query returns no match or the cursor returns the document at the "`end`" of the collection and the application then deletes that document. The following example shows how to create and use an infinite stream query: + +.Infinite Stream queries with ReactiveMongoOperations +==== +[source,java] +---- +Flux stream = template.tail(query(where("name").is("Joe")), Person.class); + +Disposable subscription = stream.doOnNext(person -> System.out.println(person)).subscribe(); + +// … + +// Later: Dispose the subscription to close the stream +subscription.dispose(); +---- +==== + +Spring Data MongoDB Reactive repositories support infinite streams by annotating a query method with `@Tailable`. This works for methods that return `Flux` and other reactive types capable of emitting multiple elements, as the following example shows: + +.Infinite Stream queries with ReactiveMongoRepository +==== +[source,java] +---- + +public interface PersonRepository extends ReactiveMongoRepository { + + @Tailable + Flux findByFirstname(String firstname); + +} + +Flux stream = repository.findByFirstname("Joe"); + +Disposable subscription = stream.doOnNext(System.out::println).subscribe(); + +// … + +// Later: Dispose the subscription to close the stream +subscription.dispose(); +---- +====