Skip to content

DATAMONGO-1176 - Add support for reactive data access. #393

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 26 commits into from

Conversation

mp911de
Copy link
Member

@mp911de mp911de commented Sep 26, 2016

We now support reactive data access with Spring Data MongoDB using MongoDB's ReactiveStreams driver. Blocking and reactive data access require two drivers hence two connections are required that require configuration of each driver with their according MongoTemplate/ReactiveMongoTemplate.

ReactiveMongoTemplate uses Project Reactor wrapper types Mono and Flux to implement ReactiveMongoTemplate and repository support. Reactive template supports common operations such as:

  • Index Operation
  • Collection retrieval/creation
  • Various find methods (by Id, by Query)
  • Geospatial queries
  • Insert/Save/Update, findAndModify and findAndRemove methods
  • Exists and Count projections
  • Tailing (Infinite Streams)
  • Reactive Callback methods

Not supported:

  • Aggregations
  • Map/Reduce
Person person = new Person("Dave", 25);

template.insert(person) //
    .then(template.updateFirst(new Query(Criteria.where("age").is(25)), new Update().set("firstName", "Sven"),
            Person.class)) //
    .flatMap(p -> template.find(new Query(Criteria.where("age").is(25)), Person.class))
    .subscribeWith(TestSubscriber.create()) //
    .await() //
    .assertValuesWith(result -> {
        assertThat(result.getFirstName(), is(equalTo("Sven")));
    });

Reactive Repository support is built on top of ReactiveMongoTemplate using ReactiveMongoRepository as the store-specific base repository. Reactive repositories are enabled by using @EnableReactiveMongoRepositories on a @Configuration class to opt-in for reactive support. Reactive repositories can be composed of a reactive base interface such as

  • ReactiveCrudRepository
  • ReactiveSortingRepository
  • RxJava1CrudRepository
  • RxJava1SortingRepository

and are identified as reactive repository if one method uses a reactive wrapper type (such as Flux or Observable). If a reactive repository is discovered, it's not implemented by the blocking repository support but with the reactive repository factory. Blocking methods are not (yet) synchronized when using a reactive repository so each repository method must use a reactive wrapper result type. Reactive repository support with Spring Data allows using RxJava1 and Project Reactor types to declare repository methods. Reactive wrapper types are internally converted so the composition library choice on repository level is left up to the user.

Reactive MongoDB repository feature coverage is similar to blocking repository support:

  • Query Methods using String queries and Query Derivation
  • Geospatial queries (Flux<T> and Flux<GeoResult<T>> without GeoPage/GeoResults support)
  • Delete Queries
  • JSON based query methods and field restriction
  • Full-text queries
  • Projections
  • Infinite Streams
@Configuration
@EnableReactiveMongoRepositories
class ApplicationConfig extends AbstractReactiveMongoConfiguration {

  @Override
  protected String getDatabaseName() {
    return "e-store";
  }

  @Override
  public MongoClient mongoClient() {
    return MongoClients.create();
  }

  @Override
  protected String getMappingBasePackage() {
    return "com.springdata.mongodb"
  }
}

public interface PersonRepository extends ReactiveSortingRepository<Person, String> {

  Flux<Person> findByFirstname(String firstname);

  Flux<Person> findByFirstname(Publisher<String> firstname);

  Flux<Person> findByFirstnameOrderByLastname(String firstname, Pageable pageable);

  Mono<Person> findByFirstnameAndLastname(String firstname, String lastname);

  Flux<Person> findByLocationNear(Point location, Distance distance);

  Flux<GeoResult<Person>> findByLocationNear(Point location, Distance min, Distance max);

  @InfiniteStream
  Flux<Person> findByFirstname(String firstname);
}

public interface PersonRepository extends RxJava1SortingRepository<Person, String> {

  Observable<Person> findByFirstname(String firstname);

  Observable<Person> findByFirstname(Single<String> firstname);

  Observable<Person> findByFirstnameOrderByLastname(String firstname, Pageable pageable);

  Single<Person> findByFirstnameAndLastname(String firstname, String lastname);

  Observable<Person> findByLocationNear(Point location, Distance distance);

  Observable<GeoResult<Person>> findByLocationNear(Point location, Distance min, Distance max);

  @InfiniteStream
  Observable<Person> findByFirstname(String firstname);
}

Related ticket: DATAMONGO-1444
Dependencies:

LinkedList and others added 2 commits October 27, 2016 14:31
SpringDataMongodbQuery is exposed publicly in QuerydslRepositorySupport, that's we've got to make it public to make sure class to the exposed methods from outside the package actually compile.

Original pull request: #401.
Extended license years in copyright header.

Original pull request: #401.
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ReactiveMongoOperations#save(java.lang.Object)
*/
public <T> Mono<T> save(T objectToSave) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one should check that T is not a collection/Publisher. Otherwise, it's very easy to pass in objects that are not intended for saving (save(Flux.just(…)).

odrotbohm and others added 5 commits November 2, 2016 09:52
…ated, non-ObjectId on batch inserts.

The methods in MongoTemplate inserting a batch of documents previously only returned database generated identifiers, more especially ObjectId ones. This caused non-ObjectId identifiers potentially generated by other parties — i.e. an event listener reacting to a BeforeSaveEvent — not being considered for source object identifier population.

This commit adds a workaround augmenting the list of database generated identifiers with the ones actually present in the documents to be inserted. A follow-up ticket DATAMONGO-1519 was created to track the removal of the workaround in favor of a proper fix unfortunately requiring a change in public API (so a 2.0 candidate only).

Related tickets: DATAMONGO-1519.
We now make sure to comply to the API requirements of mongo-java-driver 3.4 (in current beta1) by using empty DBObjects instead of null, ignoring non appropriate replication settings and cleaning up tests after execution.

Original pull request: #394.
… field spec.

We now make sure not to eagerly attempt to convert given query parameters into a mongo specific format by calling toString() the query object, but rather delegate this to another step later in the chain.

Original pull request: #404.
We now use more type information to create a better empty collection in the first place. The previous algorithm always used an empty HashSet plus a subsequent conversion using the raw collection type. Especially the latter caused problems for EnumSets as the conversion into one requires the presence of component type information.

We now use Spring's collection factory and more available type information to create a proper collection in the first place and only rely on a subsequent conversion for arrays.
@odrotbohm odrotbohm force-pushed the issue/DATAMONGO-1444 branch from beac4af to 03eba87 Compare November 14, 2016 07:56
@mp911de mp911de force-pushed the issue/DATAMONGO-1444 branch 2 times, most recently from 6f302e8 to 411f2d3 Compare November 14, 2016 15:45
mp911de and others added 13 commits November 14, 2016 17:49
Upgraded to Spring Data Build parent 2.0 snapshots and Spring Data Commons 2.0 snapshots. Removed obsolete distribution key property. Removed obsolete template.mf.
…h Spring 5 baseline.

Upgrade:
* Hibernate Validator to 5.2.4.Final
* JPA API to 2.1.1
* Hibernate Core to 5.2.1.Final
We use the Document API when interacting with the MongoDB Java Driver. This allows us to make use of new features and enables us to use the Codec API and prepares the project for future enhancements concerning the drivers the reactive API.
- Remove dropDups assertion as the MongoDB 3 driver does no longer provide dropDups even if running agains a MongoDB v2.6.7.
- Remove mongo-next build profile as we're based on the Mongo 3 driver now.
- Map update object and merge set operations.
- Update licenses headers.
- Renname variables and methods from dbo -> document.
- Remove deprecations.
- Remove unused code blocks.
- Upgrade to MongoDB Java Driver 3.3
Replace DbObject in documentation with Document. Fix typos. Change dbObject variable names to document. Improve error messages. Remove unused code.
Replace DbObject in documentation with Document. Fix typos. Change dbObject variable names to document.
Reactive MongoDB repository can now be composed from Project Reactor and RxJava types for method arguments and return types. Query methods and methods from the base/implementation classes can be invoked with a conversion of input/output types.
- Update Javadoc comments and reference documentation.
- Introduce Adapter for blocking IndexOperations.
- Remove transaction synchronization.
- Remove unused types.
- Remove dropDupos options from indexes.
- Prevent usage of Querydsl along with reactive repository.
- Use ReactiveQueryMethod in ReactiveMongoQuery.
- Adopt RxJava to RxJava1 repository interface renaming.
- Remove ReactiveChunk, Slice and Page.
- Update documentation.
- Prevent sliced/paged query execution.
Accept Mono<Collection<T>> instead of Publisher<T> to get rid of hidden buffer call inside of MongoTemplate.
mp911de and others added 5 commits November 14, 2016 17:50
…or blocking repository usage.

Use ReactiveWrapperConverters for reactive wrapper type conversion to not require Project Reactor for blocking repository usage.
Removed unused references to ConversionService from repository query implementations.
…ation.

We now use the newly introduced ….useRepositoryConfiguration(…) in the module specific RepositoryConfigurationExtension implementations to distinguish between reactive and non-reactive repositories.

Removed RepositoryType class as it was only used by the previous repository typ detection.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants