diff --git a/src/main/antora/modules/ROOT/nav.adoc b/src/main/antora/modules/ROOT/nav.adoc index c0afb19dc..2d96f5189 100644 --- a/src/main/antora/modules/ROOT/nav.adoc +++ b/src/main/antora/modules/ROOT/nav.adoc @@ -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[] diff --git a/src/main/antora/modules/ROOT/pages/mongodb/mongo-query/fluent-template-api.adoc b/src/main/antora/modules/ROOT/pages/mongodb/mongo-query/fluent-template-api.adoc deleted file mode 100644 index e5f1e0aff..000000000 --- a/src/main/antora/modules/ROOT/pages/mongodb/mongo-query/fluent-template-api.adoc +++ /dev/null @@ -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 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 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 <> 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 results = mongoOps.query(SWCharacter.class) - .as(Jedi.class) - .near(alderaan) // NearQuery.near(-73.9667, 40.78).maxDis… - .all(); ----- -==== - diff --git a/src/main/antora/modules/ROOT/pages/mongodb/mongo-query/template.adoc b/src/main/antora/modules/ROOT/pages/mongodb/mongo-query/template.adoc deleted file mode 100644 index af7cad788..000000000 --- a/src/main/antora/modules/ROOT/pages/mongodb/mongo-query/template.adoc +++ /dev/null @@ -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 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)` 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)` 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)` 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]. - diff --git a/src/main/antora/modules/ROOT/pages/mongodb/template-api.adoc b/src/main/antora/modules/ROOT/pages/mongodb/template-api.adoc index 34dba652e..716c95799 100644 --- a/src/main/antora/modules/ROOT/pages/mongodb/template-api.adoc +++ b/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 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 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 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 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 <> 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 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. diff --git a/src/main/antora/modules/ROOT/pages/mongodb/template-query-operations.adoc b/src/main/antora/modules/ROOT/pages/mongodb/template-query-operations.adoc index b2891622a..5a65f0a92 100644 --- a/src/main/antora/modules/ROOT/pages/mongodb/template-query-operations.adoc +++ b/src/main/antora/modules/ROOT/pages/mongodb/template-query-operations.adoc @@ -17,5 +17,212 @@ List 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 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 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)` 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)` 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)` 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`. +==== +