diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AddFieldsOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AddFieldsOperation.java
index 984cfdc8c..8ebc744ad 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AddFieldsOperation.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AddFieldsOperation.java
@@ -151,6 +151,13 @@ public class AddFieldsOperation extends DocumentEnhancingOperation {
valueMap.put(field, value instanceof String ? Fields.fields((String) value) : value);
return AddFieldsOperationBuilder.this;
}
+
+ @Override
+ public AddFieldsOperationBuilder withValueOfExpression(String operation, Object... values) {
+
+ valueMap.put(field, new ExpressionProjection(operation, values));
+ return AddFieldsOperationBuilder.this;
+ }
};
}
@@ -179,7 +186,15 @@ public class AddFieldsOperation extends DocumentEnhancingOperation {
* @return new instance of {@link AddFieldsOperation}.
*/
AddFieldsOperationBuilder withValueOf(Object value);
- }
+ /**
+ * Adds a generic projection for the current field.
+ *
+ * @param operation the operation key, e.g. {@code $add}.
+ * @param values the values to be set for the projection operation.
+ * @return new instance of {@link AddFieldsOperation}.
+ */
+ AddFieldsOperationBuilder withValueOfExpression(String operation, Object... values);
+ }
}
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Aggregation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Aggregation.java
index 44376d6e8..efcb26f24 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Aggregation.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Aggregation.java
@@ -119,7 +119,7 @@ public class Aggregation {
/**
* Creates a new {@link AggregationUpdate} from the given {@link AggregationOperation}s.
- *
+ *
* @param operations can be {@literal empty} but must not be {@literal null}.
* @return new instance of {@link AggregationUpdate}.
* @since 3.0
@@ -202,11 +202,16 @@ public class Aggregation {
Assert.notNull(aggregationOperations, "AggregationOperations must not be null!");
Assert.notNull(options, "AggregationOptions must not be null!");
- // check $out is the last operation if it exists
+ // check $out/$merge is the last operation if it exists
for (AggregationOperation aggregationOperation : aggregationOperations) {
+
if (aggregationOperation instanceof OutOperation && !isLast(aggregationOperation, aggregationOperations)) {
throw new IllegalArgumentException("The $out operator must be the last stage in the pipeline.");
}
+
+ if (aggregationOperation instanceof MergeOperation && !isLast(aggregationOperation, aggregationOperations)) {
+ throw new IllegalArgumentException("The $merge operator must be the last stage in the pipeline.");
+ }
}
this.operations = aggregationOperations;
@@ -236,6 +241,20 @@ public class Aggregation {
return "_id";
}
+ /**
+ * Obtain an {@link AddFieldsOperationBuilder builder} instance to create a new {@link AddFieldsOperation}.
+ *
+ * Starting in version 4.2, MongoDB adds a new aggregation pipeline stage {@link AggregationUpdate#set $set} that is
+ * an alias for {@code $addFields}.
+ *
+ * @return new instance of {@link AddFieldsOperationBuilder}.
+ * @see AddFieldsOperation
+ * @since 3.0
+ */
+ public static AddFieldsOperationBuilder addFields() {
+ return AddFieldsOperation.builder();
+ }
+
/**
* Creates a new {@link ProjectionOperation} including the given fields.
*
@@ -495,6 +514,30 @@ public class Aggregation {
return new MatchOperation(criteria);
}
+ /**
+ * Creates a new {@link GeoNearOperation} instance from the given {@link NearQuery} and the {@code distanceField}. The
+ * {@code distanceField} defines output field that contains the calculated distance.
+ *
+ * @param query must not be {@literal null}.
+ * @param distanceField must not be {@literal null} or empty.
+ * @return
+ * @since 1.7
+ */
+ public static GeoNearOperation geoNear(NearQuery query, String distanceField) {
+ return new GeoNearOperation(query, distanceField);
+ }
+
+ /**
+ * Obtain a {@link MergeOperationBuilder builder} instance to create a new {@link MergeOperation}.
+ *
+ * @return new instance of {@link MergeOperationBuilder}.
+ * @see MergeOperation
+ * @since 3.0
+ */
+ public static MergeOperationBuilder merge() {
+ return MergeOperation.builder();
+ }
+
/**
* Creates a new {@link OutOperation} using the given collection name. This operation must be the last operation in
* the pipeline.
@@ -636,41 +679,6 @@ public class Aggregation {
return Fields.from(field(name, target));
}
- /**
- * Creates a new {@link GeoNearOperation} instance from the given {@link NearQuery} and the {@code distanceField}. The
- * {@code distanceField} defines output field that contains the calculated distance.
- *
- * @param query must not be {@literal null}.
- * @param distanceField must not be {@literal null} or empty.
- * @return
- * @since 1.7
- */
- public static GeoNearOperation geoNear(NearQuery query, String distanceField) {
- return new GeoNearOperation(query, distanceField);
- }
-
- /**
- * Obtain a {@link MergeOperationBuilder builder} instance to create a new {@link MergeOperation}.
- *
- * @return new instance of {@link MergeOperationBuilder}.
- * @see MergeOperation
- * @since 3.0
- */
- public static MergeOperationBuilder merge() {
- return MergeOperation.builder();
- }
-
- /**
- * Obtain an {@link AddFieldsOperationBuilder builder} instance to create a new {@link AddFieldsOperation}.
- *
- * @return new instance of {@link AddFieldsOperationBuilder}.
- * @see AddFieldsOperation
- * @since 3.0
- */
- public static AddFieldsOperationBuilder addFields() {
- return AddFieldsOperation.builder();
- }
-
/**
* Returns a new {@link AggregationOptions.Builder}.
*
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationUpdate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationUpdate.java
index 5866f2a1e..c97ca3974 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationUpdate.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationUpdate.java
@@ -79,7 +79,7 @@ import org.springframework.util.Assert;
public class AggregationUpdate extends Aggregation implements UpdateDefinition {
private boolean isolated = false;
- private Set keysTouched = new HashSet<>();
+ private final Set keysTouched = new HashSet<>();
/**
* Create new {@link AggregationUpdate}.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DocumentEnhancingOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DocumentEnhancingOperation.java
index 9c078de59..1562bce70 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DocumentEnhancingOperation.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DocumentEnhancingOperation.java
@@ -24,16 +24,18 @@ import java.util.stream.Collectors;
import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
import org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation;
+import org.springframework.util.Assert;
/**
- * Base class for common taks required by {@link SetOperation} and {@link AddFieldsOperation}.
+ * Base class for common tasks required by {@link SetOperation} and {@link AddFieldsOperation}.
*
* @author Christoph Strobl
* @since 3.0
*/
abstract class DocumentEnhancingOperation implements InheritsFieldsAggregationOperation {
- private Map