Polishing.
Reorder methods. Tweak Javadoc and documentation wording. Mention projection expressions in the what's new section. Reformat code. See #3583 Original pull request: #3585.
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.bson.codecs.DocumentCodec;
|
||||
import org.bson.codecs.configuration.CodecRegistry;
|
||||
@@ -30,15 +32,15 @@ import org.springframework.util.StringUtils;
|
||||
* binding of placeholders like {@code ?0} is delayed upon first call on the the target {@link Document} via
|
||||
* {@link #toDocument()}.
|
||||
* <p />
|
||||
*
|
||||
*
|
||||
* <pre class="code">
|
||||
* $toUpper : $name -> { '$toUpper' : '$name' }
|
||||
*
|
||||
*
|
||||
* { '$toUpper' : '$name' } -> { '$toUpper' : '$name' }
|
||||
*
|
||||
*
|
||||
* { '$toUpper' : '?0' }, "$name" -> { '$toUpper' : '$name' }
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* Some types might require a special {@link org.bson.codecs.Codec}. If so, make sure to provide a {@link CodecRegistry}
|
||||
* containing the required {@link org.bson.codecs.Codec codec} via {@link #withCodecRegistry(CodecRegistry)}.
|
||||
*
|
||||
@@ -49,11 +51,9 @@ public class BindableMongoExpression implements MongoExpression {
|
||||
|
||||
private final String expressionString;
|
||||
|
||||
@Nullable //
|
||||
private final CodecRegistryProvider codecRegistryProvider;
|
||||
private final @Nullable CodecRegistryProvider codecRegistryProvider;
|
||||
|
||||
@Nullable //
|
||||
private final Object[] args;
|
||||
private final @Nullable Object[] args;
|
||||
|
||||
private final Lazy<Document> target;
|
||||
|
||||
@@ -118,16 +118,8 @@ public class BindableMongoExpression implements MongoExpression {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BindableMongoExpression{" + "expressionString='" + expressionString + '\'' + ", args=" + args + '}';
|
||||
}
|
||||
|
||||
private String wrapJsonIfNecessary(String json) {
|
||||
|
||||
if (StringUtils.hasText(json) && (json.startsWith("{") && json.endsWith("}"))) {
|
||||
return json;
|
||||
}
|
||||
|
||||
return "{" + json + "}";
|
||||
return "BindableMongoExpression{" + "expressionString='" + expressionString + '\'' + ", args="
|
||||
+ Arrays.toString(args) + '}';
|
||||
}
|
||||
|
||||
private Document parse() {
|
||||
@@ -148,4 +140,13 @@ public class BindableMongoExpression implements MongoExpression {
|
||||
: new ParameterBindingDocumentCodec(codecRegistryProvider.getCodecRegistry());
|
||||
return codec.decode(expression, args);
|
||||
}
|
||||
|
||||
private static String wrapJsonIfNecessary(String json) {
|
||||
|
||||
if (StringUtils.hasText(json) && (json.startsWith("{") && json.endsWith("}"))) {
|
||||
return json;
|
||||
}
|
||||
|
||||
return "{" + json + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,13 +39,6 @@ package org.springframework.data.mongodb;
|
||||
@FunctionalInterface
|
||||
public interface MongoExpression {
|
||||
|
||||
/**
|
||||
* Obtain the native {@link org.bson.Document} representation.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
org.bson.Document toDocument();
|
||||
|
||||
/**
|
||||
* Create a new {@link MongoExpression} from plain {@link String} (eg. {@code $toUpper : $name}). <br />
|
||||
* The given expression will be wrapped with <code>{ ... }</code> to match an actual MongoDB {@link org.bson.Document}
|
||||
@@ -70,4 +63,11 @@ public interface MongoExpression {
|
||||
static MongoExpression create(String expression, Object... args) {
|
||||
return new BindableMongoExpression(expression, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the native {@link org.bson.Document} representation.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
org.bson.Document toDocument();
|
||||
}
|
||||
|
||||
@@ -28,18 +28,6 @@ import org.springframework.data.mongodb.MongoExpression;
|
||||
*/
|
||||
public interface AggregationExpression extends MongoExpression {
|
||||
|
||||
/**
|
||||
* Obtain the as is (unmapped) representation of the {@link AggregationExpression}. Use
|
||||
* {@link #toDocument(AggregationOperationContext)} with a matching {@link AggregationOperationContext context} to
|
||||
* engage domain type mapping including field name resolution.
|
||||
*
|
||||
* @see org.springframework.data.mongodb.MongoExpression#toDocument()
|
||||
*/
|
||||
@Override
|
||||
default Document toDocument() {
|
||||
return toDocument(Aggregation.DEFAULT_CONTEXT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AggregationExpression} out of a given {@link MongoExpression} to ensure the resulting
|
||||
* {@link MongoExpression#toDocument() Document} is mapped against the {@link AggregationOperationContext}. <br />
|
||||
@@ -58,6 +46,18 @@ public interface AggregationExpression extends MongoExpression {
|
||||
return (context) -> context.getMappedObject(expression.toDocument());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the as is (unmapped) representation of the {@link AggregationExpression}. Use
|
||||
* {@link #toDocument(AggregationOperationContext)} with a matching {@link AggregationOperationContext context} to
|
||||
* engage domain type mapping including field name resolution.
|
||||
*
|
||||
* @see org.springframework.data.mongodb.MongoExpression#toDocument()
|
||||
*/
|
||||
@Override
|
||||
default Document toDocument() {
|
||||
return toDocument(Aggregation.DEFAULT_CONTEXT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns the {@link AggregationExpression} into a {@link Document} within the given
|
||||
* {@link AggregationOperationContext}.
|
||||
|
||||
@@ -63,21 +63,21 @@ public class Field {
|
||||
* result.
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
*
|
||||
* // { 'name' : { '$toUpper' : '$name' } }
|
||||
*
|
||||
*
|
||||
* // native MongoDB expression
|
||||
* .project(MongoExpression.expressionFromString("'$toUpper' : '$name'")).as("name");
|
||||
*
|
||||
*
|
||||
* // Aggregation Framework expression
|
||||
* .project(StringOperators.valueOf("name").toUpper()).as("name");
|
||||
*
|
||||
*
|
||||
* // Aggregation Framework SpEL expression
|
||||
* .project(AggregationSpELExpression.expressionOf("toUpper(name)")).as("name");
|
||||
* </pre>
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return new instance of {@link FieldProjectionExpression} - you still need to define the target field name via
|
||||
* @return new instance of {@link FieldProjectionExpression}. Define the target field name through
|
||||
* {@link FieldProjectionExpression#as(String) as(String)}.
|
||||
* @since 3.2
|
||||
*/
|
||||
@@ -277,15 +277,15 @@ public class Field {
|
||||
|
||||
/**
|
||||
* Intermediate builder part for projecting a {@link MongoExpression} to a result field.
|
||||
*
|
||||
*
|
||||
* @since 3.2
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public interface FieldProjectionExpression {
|
||||
|
||||
/**
|
||||
* Set the name to be used in the result.
|
||||
*
|
||||
* Set the name to be used in the result and return a {@link Field}.
|
||||
*
|
||||
* @param name must not be {@literal null}.
|
||||
* @return the calling instance {@link Field}.
|
||||
*/
|
||||
|
||||
@@ -39,6 +39,8 @@ import org.springframework.data.mongodb.test.util.MongoTestTemplate;
|
||||
import org.springframework.data.mongodb.test.util.Template;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link org.springframework.data.mongodb.core.query.Field}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@ExtendWith(MongoTemplateExtension.class)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
== What's New in Spring Data MongoDB 3.2
|
||||
|
||||
* Support for <<embedded-entities,Embedded Types>> to unwrap nested objects into the parent `Document`.
|
||||
* <<mongo-template.querying.field-selection,Support expressions to define field projections>>.
|
||||
|
||||
[[new-features.3.1]]
|
||||
== What's New in Spring Data MongoDB 3.1
|
||||
|
||||
@@ -1251,7 +1251,7 @@ The `Query` class has some additional methods that provide options for the query
|
||||
==== Selecting fields
|
||||
|
||||
MongoDB supports https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results/[projecting fields] returned by a query.
|
||||
A projection can in- & exclude fields (the `_id` field is always included unless explicitly excluded) based on their name.
|
||||
A projection can include and exclude fields (the `_id` field is always included unless explicitly excluded) based on their name.
|
||||
|
||||
.Selecting result fields
|
||||
====
|
||||
@@ -1268,13 +1268,13 @@ public class Person {
|
||||
Address address;
|
||||
}
|
||||
|
||||
query.fields().include("lastname"); <1>
|
||||
query.fields().include("lastname"); <1>
|
||||
|
||||
query.fields().exclude("id").include("lastname") <2>
|
||||
|
||||
query.fields().include("address") <3>
|
||||
query.fields().include("address") <3>
|
||||
|
||||
query.fields().include("address.city") <4>
|
||||
query.fields().include("address.city") <4>
|
||||
|
||||
|
||||
----
|
||||
@@ -1284,31 +1284,31 @@ query.fields().include("address.city") <4>
|
||||
<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 it is possible to use the aggregation expressions syntax for field projections as shown below.
|
||||
Starting with MongoDB 4.4 you can use aggregation expressions for field projections as shown below:
|
||||
|
||||
.Computing result fields with expressions
|
||||
.Computing result fields using expressions
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
query.fields()
|
||||
.project(MongoExpression.create("'$toUpper' : '$last_name'")) <1>
|
||||
.as("last_name"); <2>
|
||||
.project(MongoExpression.create("'$toUpper' : '$last_name'")) <1>
|
||||
.as("last_name"); <2>
|
||||
|
||||
query.fields()
|
||||
.project(StringOperators.valueOf("lastname").toUpper()) <3>
|
||||
.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 names must refer to the ones of the document within the database.
|
||||
<2> Assign the field name that shall hold the expression result in the target document. The resulting field name will never be mapped against the domain model.
|
||||
<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 <<mongodb.repositories.queries.json-based>>.
|
||||
`@Query(fields="…")` allows usage of expression field projections at `Repository` level as described in <<mongodb.repositories.queries.json-based>>.
|
||||
|
||||
[[mongo-template.querying]]
|
||||
=== Methods for Querying for Documents
|
||||
|
||||
Reference in New Issue
Block a user