Browse Source

move fluent template API and distinct queries

labs/antora
Christoph Strobl 2 years ago
parent
commit
678b0a65b2
No known key found for this signature in database
GPG Key ID: 8CC1AB53391458C8
  1. 1
      src/main/antora/modules/ROOT/nav.adoc
  2. 56
      src/main/antora/modules/ROOT/pages/mongodb/mongo-query/fluent-template-api.adoc
  3. 144
      src/main/antora/modules/ROOT/pages/mongodb/mongo-query/template.adoc
  4. 61
      src/main/antora/modules/ROOT/pages/mongodb/template-api.adoc
  5. 209
      src/main/antora/modules/ROOT/pages/mongodb/template-query-operations.adoc

1
src/main/antora/modules/ROOT/nav.adoc

@ -18,7 +18,6 @@ @@ -18,7 +18,6 @@
**** xref:mongodb/mongo-query/geo-json.adoc[]
**** xref:mongodb/mongo-query/textsearch.adoc[]
**** xref:mongodb/mongo-query/collation.adoc[]
**** xref:mongodb/mongo-query/fluent-template-api.adoc[]
**** xref:mongodb/mongo-query/kotlin-support.adoc[]
**** xref:mongodb/mongo-query/additional-options.adoc[]
*** xref:mongodb/mongo-query-count.adoc[]

56
src/main/antora/modules/ROOT/pages/mongodb/mongo-query/fluent-template-api.adoc

@ -1,56 +0,0 @@ @@ -1,56 +0,0 @@
[[mongo.query.fluent-template-api]]
= Fluent Template API
The `MongoOperations` interface is one of the central components when it comes to more low-level interaction with MongoDB. It offers a wide range of methods covering needs from collection creation, index creation, and CRUD operations to more advanced functionality, such as Map-Reduce and aggregations.
You can find multiple overloads for each method. Most of them cover optional or nullable parts of the API.
`FluentMongoOperations` provides a more narrow interface for the common methods of `MongoOperations` and provides a more readable, fluent API.
The entry points (`insert(…)`, `find(…)`, `update(…)`, and others) follow a natural naming schema based on the operation to be run. Moving on from the entry point, the API is designed to offer only context-dependent methods that lead to a terminating method that invokes the actual `MongoOperations` counterpart -- the `all` method in the case of the following example:
====
[source,java]
----
List<SWCharacter> all = ops.find(SWCharacter.class)
.inCollection("star-wars") <1>
.all();
----
<1> Skip this step if `SWCharacter` defines the collection with `@Document` or if you use the class name as the collection name, which is fine.
====
Sometimes, a collection in MongoDB holds entities of different types, such as a `Jedi` within a collection of `SWCharacters`.
To use different types for `Query` and return value mapping, you can use `as(Class<?> targetType)` to map results differently, as the following example shows:
====
[source,java]
----
List<Jedi> all = ops.find(SWCharacter.class) <1>
.as(Jedi.class) <2>
.matching(query(where("jedi").is(true)))
.all();
----
<1> The query fields are mapped against the `SWCharacter` type.
<2> Resulting documents are mapped into `Jedi`.
====
TIP: You can directly apply <<projections>> to result documents by providing the target type via `as(Class<?>)`.
NOTE: Using projections allows `MongoTemplate` to optimize result mapping by limiting the actual response to fields required
by the projection target type. This applies as long as the `Query` itself does not contain any field restriction and the
target type is a closed interface or DTO projection.
WARNING: Projections must not be applied to xref:reference/document-references.adoc[DBRefs].
You can switch between retrieving a single entity and retrieving multiple entities as a `List` or a `Stream` through the terminating methods: `first()`, `one()`, `all()`, or `stream()`.
When writing a geo-spatial query with `near(NearQuery)`, the number of terminating methods is altered to include only the methods that are valid for running a `geoNear` command in MongoDB (fetching entities as a `GeoResult` within `GeoResults`), as the following example shows:
====
[source,java]
----
GeoResults<Jedi> results = mongoOps.query(SWCharacter.class)
.as(Jedi.class)
.near(alderaan) // NearQuery.near(-73.9667, 40.78).maxDis…
.all();
----
====

144
src/main/antora/modules/ROOT/pages/mongodb/mongo-query/template.adoc

@ -1,144 +0,0 @@ @@ -1,144 +0,0 @@
[[mongodb-template-query]]
= Querying Documents in a Collection
Earlier, we saw how to retrieve a single document by using the `findOne` and `findById` methods on `MongoTemplate`. These methods return a single domain object. We can also query for a collection of documents to be returned as a list of domain objects. Assuming that we have a number of `Person` objects with name and age stored as documents in a collection and that each person has an embedded account document with a balance, we can now run a query using the following code:
.Querying for documents using the MongoTemplate
====
[source,java]
----
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;
// ...
List<Person> result = template.query(Person.class)
.matching(query(where("age").lt(50).and("accounts.balance").gt(1000.00d)))
.all();
----
====
All find methods take a `Query` object as a parameter. This object defines the criteria and options used to perform the query. The criteria are specified by using a `Criteria` object that has a static factory method named `where` to instantiate a new `Criteria` object. We recommend using static imports for `org.springframework.data.mongodb.core.query.Criteria.where` and `Query.query` to make the query more readable.
The query should return a list of `Person` objects that meet the specified criteria. The rest of this section lists the methods of the `Criteria` and `Query` classes that correspond to the operators provided in MongoDB. Most methods return the `Criteria` object, to provide a fluent style for the API.
[[mongodb-template-query.criteria]]
== Methods for the Criteria Class
The `Criteria` class provides the following methods, all of which correspond to operators in MongoDB:
* `Criteria` *all* `(Object o)` Creates a criterion using the `$all` operator
* `Criteria` *and* `(String key)` Adds a chained `Criteria` with the specified `key` to the current `Criteria` and returns the newly created one
* `Criteria` *andOperator* `(Criteria... criteria)` Creates an and query using the `$and` operator for all of the provided criteria (requires MongoDB 2.0 or later)
* `Criteria` *andOperator* `(Collection<Criteria> criteria)` Creates an and query using the `$and` operator for all of the provided criteria (requires MongoDB 2.0 or later)
* `Criteria` *elemMatch* `(Criteria c)` Creates a criterion using the `$elemMatch` operator
* `Criteria` *exists* `(boolean b)` Creates a criterion using the `$exists` operator
* `Criteria` *gt* `(Object o)` Creates a criterion using the `$gt` operator
* `Criteria` *gte* `(Object o)` Creates a criterion using the `$gte` operator
* `Criteria` *in* `(Object... o)` Creates a criterion using the `$in` operator for a varargs argument.
* `Criteria` *in* `(Collection<?> collection)` Creates a criterion using the `$in` operator using a collection
* `Criteria` *is* `(Object o)` Creates a criterion using field matching (`{ key:value }`). If the specified value is a document, the order of the fields and exact equality in the document matters.
* `Criteria` *lt* `(Object o)` Creates a criterion using the `$lt` operator
* `Criteria` *lte* `(Object o)` Creates a criterion using the `$lte` operator
* `Criteria` *mod* `(Number value, Number remainder)` Creates a criterion using the `$mod` operator
* `Criteria` *ne* `(Object o)` Creates a criterion using the `$ne` operator
* `Criteria` *nin* `(Object... o)` Creates a criterion using the `$nin` operator
* `Criteria` *norOperator* `(Criteria... criteria)` Creates an nor query using the `$nor` operator for all of the provided criteria
* `Criteria` *norOperator* `(Collection<Criteria> criteria)` Creates an nor query using the `$nor` operator for all of the provided criteria
* `Criteria` *not* `()` Creates a criterion using the `$not` meta operator which affects the clause directly following
* `Criteria` *orOperator* `(Criteria... criteria)` Creates an or query using the `$or` operator for all of the provided criteria
* `Criteria` *orOperator* `(Collection<Criteria> criteria)` Creates an or query using the `$or` operator for all of the provided criteria
* `Criteria` *regex* `(String re)` Creates a criterion using a `$regex`
* `Criteria` *sampleRate* `(double sampleRate)` Creates a criterion using the `$sampleRate` operator
* `Criteria` *size* `(int s)` Creates a criterion using the `$size` operator
* `Criteria` *type* `(int t)` Creates a criterion using the `$type` operator
* `Criteria` *matchingDocumentStructure* `(MongoJsonSchema schema)` Creates a criterion using the `$jsonSchema` operator for xref:reference/mongo-json-schema.adoc[JSON schema criteria]. `$jsonSchema` can only be applied on the top level of a query and not property specific. Use the `properties` attribute of the schema to match against nested fields.
* `Criteria` *bits()* is the gateway to https://docs.mongodb.com/manual/reference/operator/query-bitwise/[MongoDB bitwise query operators] like `$bitsAllClear`.
The Criteria class also provides the following methods for geospatial queries (see the xref:reference/mongodb/mongo-query/geospatial.adoc[GeoSpatial Queries] section to see them in action):
* `Criteria` *within* `(Circle circle)` Creates a geospatial criterion using `$geoWithin $center` operators.
* `Criteria` *within* `(Box box)` Creates a geospatial criterion using a `$geoWithin $box` operation.
* `Criteria` *withinSphere* `(Circle circle)` Creates a geospatial criterion using `$geoWithin $center` operators.
* `Criteria` *near* `(Point point)` Creates a geospatial criterion using a `$near` operation
* `Criteria` *nearSphere* `(Point point)` Creates a geospatial criterion using `$nearSphere$center` operations. This is only available for MongoDB 1.7 and higher.
* `Criteria` *minDistance* `(double minDistance)` Creates a geospatial criterion using the `$minDistance` operation, for use with $near.
* `Criteria` *maxDistance* `(double maxDistance)` Creates a geospatial criterion using the `$maxDistance` operation, for use with $near.
[[mongodb-template-query.query]]
== Methods for the Query class
The `Query` class has some additional methods that provide options for the query:
* `Query` *addCriteria* `(Criteria criteria)` used to add additional criteria to the query
* `Field` *fields* `()` used to define fields to be included in the query results
* `Query` *limit* `(int limit)` used to limit the size of the returned results to the provided limit (used for paging)
* `Query` *skip* `(int skip)` used to skip the provided number of documents in the results (used for paging)
* `Query` *with* `(Sort sort)` used to provide sort definition for the results
* `Query` *with* `(ScrollPosition position)` used to provide a scroll position (Offset- or Keyset-based pagination) to start or resume a `Scroll`
[[mongo-template.querying.field-selection]]
== Selecting fields
MongoDB supports https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results/[projecting fields] returned by a query.
A projection can include and exclude fields (the `_id` field is always included unless explicitly excluded) based on their name.
.Selecting result fields
====
[source,java]
----
public class Person {
@Id String id;
String firstname;
@Field("last_name")
String lastname;
Address address;
}
query.fields().include("lastname"); <1>
query.fields().exclude("id").include("lastname") <2>
query.fields().include("address") <3>
query.fields().include("address.city") <4>
----
<1> Result will contain both `_id` and `last_name` via `{ "last_name" : 1 }`.
<2> Result will only contain the `last_name` via `{ "_id" : 0, "last_name" : 1 }`.
<3> Result will contain the `_id` and entire `address` object via `{ "address" : 1 }`.
<4> Result will contain the `_id` and and `address` object that only contains the `city` field via `{ "address.city" : 1 }`.
====
Starting with MongoDB 4.4 you can use aggregation expressions for field projections as shown below:
.Computing result fields using expressions
====
[source,java]
----
query.fields()
.project(MongoExpression.create("'$toUpper' : '$last_name'")) <1>
.as("last_name"); <2>
query.fields()
.project(StringOperators.valueOf("lastname").toUpper()) <3>
.as("last_name");
query.fields()
.project(AggregationSpELExpression.expressionOf("toUpper(lastname)")) <4>
.as("last_name");
----
<1> Use a native expression. The used field name must refer to field names within the database document.
<2> Assign the field name to which the expression result is projected. The resulting field name is not mapped against the domain model.
<3> Use an `AggregationExpression`. Other than native `MongoExpression`, field names are mapped to the ones used in the domain model.
<4> Use SpEL along with an `AggregationExpression` to invoke expression functions. Field names are mapped to the ones used in the domain model.
====
`@Query(fields="…")` allows usage of expression field projections at `Repository` level as described in xref:reference/mongo-repositories.adoc#mongodb.repositories.queries.json-based[MongoDB JSON-based Query Methods and Field Restriction].

61
src/main/antora/modules/ROOT/pages/mongodb/template-api.adoc

@ -8,7 +8,7 @@ NOTE: Once configured, `MongoTemplate` is thread-safe and can be reused across m @@ -8,7 +8,7 @@ NOTE: Once configured, `MongoTemplate` is thread-safe and can be reused across m
The mapping between MongoDB documents and domain classes is done by delegating to an implementation of the `MongoConverter` interface.
Spring provides `MappingMongoConverter`, but you can also write your own converter.
See "`xref:reference/mongo-custom-conversions.adoc[Custom Conversions - Overriding Default Mapping]`" for more detailed information.
See "`xref:mongodb/mongo-custom-conversions.adoc[Custom Conversions - Overriding Default Mapping]`" for more detailed information.
The `MongoTemplate` class implements the interface `MongoOperations`.
In as much as possible, the methods on `MongoOperations` are named after methods available on the MongoDB driver `Collection` object, to make the API familiar to existing MongoDB developers who are used to the driver API.
@ -24,11 +24,66 @@ While the `MappingMongoConverter` can use additional metadata to specify the map @@ -24,11 +24,66 @@ While the `MappingMongoConverter` can use additional metadata to specify the map
These conventions, as well as the use of mapping annotations, are explained in the "`xref:reference/mapping.adoc[Mapping]`" chapter.
Another central feature of `MongoTemplate` is translation of exceptions thrown by the MongoDB Java driver into Spring's portable Data Access Exception hierarchy.
See "`xref:reference/mongodb/mongo-exception.adoc[Exception Translation]`" for more information.
See "`xref:mongodb/mongo-exception.adoc[Exception Translation]`" for more information.
`MongoTemplate` offers many convenience methods to help you easily perform common tasks.
However, if you need to directly access the MongoDB driver API, you can use one of several `Execute` callback methods.
The `execute` callbacks gives you a reference to either a `MongoCollection` or a `MongoDatabase` object.
See the xref:reference/mongodb/mongo-executioncallback.adoc["`Execution Callbacks`"] section for more information.
See the xref:mongodb/mongo-executioncallback.adoc["`Execution Callbacks`"] section for more information.
Being the central component when it comes to more low-level interaction with MongoDB `MongoTemplate` offers a wide range of methods covering needs from collection creation, index creation, and CRUD operations to more advanced functionality, such as Map-Reduce and aggregations.
You can find multiple overloads for each method.
Most of them cover optional or nullable parts of the API.
`FluentMongoOperations` provides a more narrow interface for the common methods of `MongoOperations` and provides a more readable, fluent API.
The entry points (`insert(…)`, `find(…)`, `update(…)`, and others) follow a natural naming schema based on the operation to be run.
Moving on from the entry point, the API is designed to offer only context-dependent methods that lead to a terminating method that invokes the actual `MongoOperations` counterpart -- the `all` method in the case of the following example:
====
[source,java]
----
List<SWCharacter> all = ops.find(SWCharacter.class)
.inCollection("star-wars") <1>
.all();
----
<1> Skip this step if `SWCharacter` defines the collection with `@Document` or if you use the class name as the collection name, which is fine.
====
Sometimes, a collection in MongoDB holds entities of different types, such as a `Jedi` within a collection of `SWCharacters`.
To use different types for `Query` and return value mapping, you can use `as(Class<?> targetType)` to map results differently, as the following example shows:
====
[source,java]
----
List<Jedi> all = ops.find(SWCharacter.class) <1>
.as(Jedi.class) <2>
.matching(query(where("jedi").is(true)))
.all();
----
<1> The query fields are mapped against the `SWCharacter` type.
<2> Resulting documents are mapped into `Jedi`.
====
TIP: You can directly apply <<projections>> to result documents by providing the target type via `as(Class<?>)`.
NOTE: Using projections allows `MongoTemplate` to optimize result mapping by limiting the actual response to fields required
by the projection target type. This applies as long as the `Query` itself does not contain any field restriction and the
target type is a closed interface or DTO projection.
WARNING: Projections must not be applied to xref:mongodb/document-references.adoc[DBRefs].
You can switch between retrieving a single entity and retrieving multiple entities as a `List` or a `Stream` through the terminating methods: `first()`, `one()`, `all()`, or `stream()`.
When writing a geo-spatial query with `near(NearQuery)`, the number of terminating methods is altered to include only the methods that are valid for running a `geoNear` command in MongoDB (fetching entities as a `GeoResult` within `GeoResults`), as the following example shows:
====
[source,java]
----
GeoResults<Jedi> results = mongoOps.query(SWCharacter.class)
.as(Jedi.class)
.near(alderaan) // NearQuery.near(-73.9667, 40.78).maxDis…
.all();
----
====
The next section contains an example of how to work with the `MongoTemplate` in the context of the Spring container.

209
src/main/antora/modules/ROOT/pages/mongodb/template-query-operations.adoc

@ -17,5 +17,212 @@ List<Person> result = mongoTemplate.find(query, Person.class); @@ -17,5 +17,212 @@ List<Person> result = mongoTemplate.find(query, Person.class);
----
====
Spring MongoDB also supports GeoSpatial queries (see the xref:mongodb/mongo-query/geospatial.adoc[GeoSpatial Queries] section) and Map-Reduce operations (see the xref:reference/mongodb/mongo-mapreduce.adoc[Map-Reduce] section.).
[[mongodb-template-query]]
== Querying Documents in a Collection
Earlier, we saw how to retrieve a single document by using the `findOne` and `findById` methods on `MongoTemplate`.
These methods return a single domain object right way or using a reactive API a `Mono` emitting a single element.
We can also query for a collection of documents to be returned as a list of domain objects.
Assuming that we have a number of `Person` objects with name and age stored as documents in a collection and that each person has an embedded account document with a balance, we can now run a query using the following code:
.Querying for documents using the MongoTemplate
[tabs]
======
Imperative::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;
// ...
List<Person> result = template.query(Person.class)
.matching(query(where("age").lt(50).and("accounts.balance").gt(1000.00d)))
.all();
----
Reactive::
+
[source,java,indent=0,subs="verbatim,quotes",role="secondary"]
----
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;
// ...
Flux<Person> result = template.query(Person.class)
.matching(query(where("age").lt(50).and("accounts.balance").gt(1000.00d)))
.all();
----
======
All find methods take a `Query` object as a parameter.
This object defines the criteria and options used to perform the query.
The criteria are specified by using a `Criteria` object that has a static factory method named `where` to instantiate a new `Criteria` object.
We recommend using static imports for `org.springframework.data.mongodb.core.query.Criteria.where` and `Query.query` to make the query more readable.
The query should return a `List` or `Flux` of `Person` objects that meet the specified criteria.
The rest of this section lists the methods of the `Criteria` and `Query` classes that correspond to the operators provided in MongoDB.
Most methods return the `Criteria` object, to provide a fluent style for the API.
[[mongodb-template-query.criteria]]
== Methods for the Criteria Class
The `Criteria` class provides the following methods, all of which correspond to operators in MongoDB:
* `Criteria` *all* `(Object o)` Creates a criterion using the `$all` operator
* `Criteria` *and* `(String key)` Adds a chained `Criteria` with the specified `key` to the current `Criteria` and returns the newly created one
* `Criteria` *andOperator* `(Criteria... criteria)` Creates an and query using the `$and` operator for all of the provided criteria (requires MongoDB 2.0 or later)
* `Criteria` *andOperator* `(Collection<Criteria> criteria)` Creates an and query using the `$and` operator for all of the provided criteria (requires MongoDB 2.0 or later)
* `Criteria` *elemMatch* `(Criteria c)` Creates a criterion using the `$elemMatch` operator
* `Criteria` *exists* `(boolean b)` Creates a criterion using the `$exists` operator
* `Criteria` *gt* `(Object o)` Creates a criterion using the `$gt` operator
* `Criteria` *gte* `(Object o)` Creates a criterion using the `$gte` operator
* `Criteria` *in* `(Object... o)` Creates a criterion using the `$in` operator for a varargs argument.
* `Criteria` *in* `(Collection<?> collection)` Creates a criterion using the `$in` operator using a collection
* `Criteria` *is* `(Object o)` Creates a criterion using field matching (`{ key:value }`). If the specified value is a document, the order of the fields and exact equality in the document matters.
* `Criteria` *lt* `(Object o)` Creates a criterion using the `$lt` operator
* `Criteria` *lte* `(Object o)` Creates a criterion using the `$lte` operator
* `Criteria` *mod* `(Number value, Number remainder)` Creates a criterion using the `$mod` operator
* `Criteria` *ne* `(Object o)` Creates a criterion using the `$ne` operator
* `Criteria` *nin* `(Object... o)` Creates a criterion using the `$nin` operator
* `Criteria` *norOperator* `(Criteria... criteria)` Creates an nor query using the `$nor` operator for all of the provided criteria
* `Criteria` *norOperator* `(Collection<Criteria> criteria)` Creates an nor query using the `$nor` operator for all of the provided criteria
* `Criteria` *not* `()` Creates a criterion using the `$not` meta operator which affects the clause directly following
* `Criteria` *orOperator* `(Criteria... criteria)` Creates an or query using the `$or` operator for all of the provided criteria
* `Criteria` *orOperator* `(Collection<Criteria> criteria)` Creates an or query using the `$or` operator for all of the provided criteria
* `Criteria` *regex* `(String re)` Creates a criterion using a `$regex`
* `Criteria` *sampleRate* `(double sampleRate)` Creates a criterion using the `$sampleRate` operator
* `Criteria` *size* `(int s)` Creates a criterion using the `$size` operator
* `Criteria` *type* `(int t)` Creates a criterion using the `$type` operator
* `Criteria` *matchingDocumentStructure* `(MongoJsonSchema schema)` Creates a criterion using the `$jsonSchema` operator for xref:reference/mongo-json-schema.adoc[JSON schema criteria]. `$jsonSchema` can only be applied on the top level of a query and not property specific. Use the `properties` attribute of the schema to match against nested fields.
* `Criteria` *bits()* is the gateway to https://docs.mongodb.com/manual/reference/operator/query-bitwise/[MongoDB bitwise query operators] like `$bitsAllClear`.
The Criteria class also provides the following methods for geospatial queries (see the xref:reference/mongodb/mongo-query/geospatial.adoc[GeoSpatial Queries] section to see them in action):
* `Criteria` *within* `(Circle circle)` Creates a geospatial criterion using `$geoWithin $center` operators.
* `Criteria` *within* `(Box box)` Creates a geospatial criterion using a `$geoWithin $box` operation.
* `Criteria` *withinSphere* `(Circle circle)` Creates a geospatial criterion using `$geoWithin $center` operators.
* `Criteria` *near* `(Point point)` Creates a geospatial criterion using a `$near` operation
* `Criteria` *nearSphere* `(Point point)` Creates a geospatial criterion using `$nearSphere$center` operations. This is only available for MongoDB 1.7 and higher.
* `Criteria` *minDistance* `(double minDistance)` Creates a geospatial criterion using the `$minDistance` operation, for use with $near.
* `Criteria` *maxDistance* `(double maxDistance)` Creates a geospatial criterion using the `$maxDistance` operation, for use with $near.
[[mongodb-template-query.query]]
== Methods for the Query class
The `Query` class has some additional methods that provide options for the query:
* `Query` *addCriteria* `(Criteria criteria)` used to add additional criteria to the query
* `Field` *fields* `()` used to define fields to be included in the query results
* `Query` *limit* `(int limit)` used to limit the size of the returned results to the provided limit (used for paging)
* `Query` *skip* `(int skip)` used to skip the provided number of documents in the results (used for paging)
* `Query` *with* `(Sort sort)` used to provide sort definition for the results
* `Query` *with* `(ScrollPosition position)` used to provide a scroll position (Offset- or Keyset-based pagination) to start or resume a `Scroll`
[[mongo-template.querying.field-selection]]
== Selecting fields
MongoDB supports https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results/[projecting fields] returned by a query.
A projection can include and exclude fields (the `_id` field is always included unless explicitly excluded) based on their name.
.Selecting result fields
====
[source,java]
----
public class Person {
@Id String id;
String firstname;
@Field("last_name")
String lastname;
Address address;
}
query.fields().include("lastname"); <1>
query.fields().exclude("id").include("lastname") <2>
query.fields().include("address") <3>
query.fields().include("address.city") <4>
----
<1> Result will contain both `_id` and `last_name` via `{ "last_name" : 1 }`.
<2> Result will only contain the `last_name` via `{ "_id" : 0, "last_name" : 1 }`.
<3> Result will contain the `_id` and entire `address` object via `{ "address" : 1 }`.
<4> Result will contain the `_id` and and `address` object that only contains the `city` field via `{ "address.city" : 1 }`.
====
Starting with MongoDB 4.4 you can use aggregation expressions for field projections as shown below:
.Computing result fields using expressions
====
[source,java]
----
query.fields()
.project(MongoExpression.create("'$toUpper' : '$last_name'")) <1>
.as("last_name"); <2>
query.fields()
.project(StringOperators.valueOf("lastname").toUpper()) <3>
.as("last_name");
query.fields()
.project(AggregationSpELExpression.expressionOf("toUpper(lastname)")) <4>
.as("last_name");
----
<1> Use a native expression. The used field name must refer to field names within the database document.
<2> Assign the field name to which the expression result is projected. The resulting field name is not mapped against the domain model.
<3> Use an `AggregationExpression`. Other than native `MongoExpression`, field names are mapped to the ones used in the domain model.
<4> Use SpEL along with an `AggregationExpression` to invoke expression functions. Field names are mapped to the ones used in the domain model.
====
`@Query(fields="…")` allows usage of expression field projections at `Repository` level as described in xref:reference/mongo-repositories.adoc#mongodb.repositories.queries.json-based[MongoDB JSON-based Query Methods and Field Restriction].
[[mongo-template.query.distinct]]
== Query Distinct Values
MongoDB provides an operation to obtain distinct values for a single field by using a query from the resulting documents.
Resulting values are not required to have the same data type, nor is the feature limited to simple types.
For retrieval, the actual result type does matter for the sake of conversion and typing. The following example shows how to query for distinct values:
.Retrieving distinct values
====
[source,java]
----
template.query(Person.class) <1>
.distinct("lastname") <2>
.all(); <3>
----
<1> Query the `Person` collection.
<2> Select distinct values of the `lastname` field. The field name is mapped according to the domain types property declaration, taking potential `@Field` annotations into account.
<3> Retrieve all distinct values as a `List` of `Object` (due to no explicit result type being specified).
====
Retrieving distinct values into a `Collection` of `Object` is the most flexible way, as it tries to determine the property value of the domain type and convert results to the desired type or mapping `Document` structures.
Sometimes, when all values of the desired field are fixed to a certain type, it is more convenient to directly obtain a correctly typed `Collection`, as shown in the following example:
.Retrieving strongly typed distinct values
====
[source,java]
----
template.query(Person.class) <1>
.distinct("lastname") <2>
.as(String.class) <3>
.all(); <4>
----
<1> Query the collection of `Person`.
<2> Select distinct values of the `lastname` field. The fieldname is mapped according to the domain types property declaration, taking potential `@Field` annotations into account.
<3> Retrieved values are converted into the desired target type -- in this case, `String`. It is also possible to map the values to a more complex type if the stored field contains a document.
<4> Retrieve all distinct values as a `List` of `String`. If the type cannot be converted into the desired target type, this method throws a `DataAccessException`.
====

Loading…
Cancel
Save