diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ObjectOperators.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ObjectOperators.java index 976d73439..b574d4a2a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ObjectOperators.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ObjectOperators.java @@ -18,8 +18,10 @@ package org.springframework.data.mongodb.core.aggregation; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Set; import org.bson.Document; +import org.springframework.data.mongodb.core.aggregation.Aggregation.SystemVariable; import org.springframework.util.Assert; /** @@ -135,6 +137,26 @@ public class ObjectOperators { public GetField getField(String fieldName) { return GetField.getField(fieldName).from(value); } + + /** + * Creates new {@link SetField aggregation expression} that takes the associated value and obtains the value of the + * field with matching name. + * + * @since 4.0 + */ + public SetField setField(String fieldName) { + return SetField.setField(fieldName).of(value); + } + + /** + * Creates new {@link SetField aggregation expression} that takes the associated value and obtains the value of the + * field with matching name. + * + * @since 4.0 + */ + public AggregationExpression removeField(String fieldName) { + return SetField.setField(fieldName).of(value).toValue(SystemVariable.REMOVE); + } } /** @@ -332,4 +354,54 @@ public class ObjectOperators { return "$getField"; } } + + /** + * {@link AggregationExpression} for {@code $setField}. + * + * @author Christoph Strobl + * @since 4.0 + */ + public static class SetField extends AbstractAggregationExpression { + + protected SetField(Object value) { + super(value); + } + + public static SetField setField(String fieldName) { + return new SetField(Collections.singletonMap("field", fieldName)); + } + + public static SetField setField(Field field) { + return setField(field.getTarget()); + } + + public SetField of(String fieldRef) { + return of(Fields.field(fieldRef)); + } + + public SetField of(AggregationExpression expression) { + return of((Object) expression); + } + + private SetField of(Object fieldRef) { + return new SetField(append("input", fieldRef)); + } + + public SetField toValueOf(String fieldReference) { + return toValue(Fields.field(fieldReference)); + } + + public SetField toValueOf(AggregationExpression expression) { + return toValue(expression); + } + + public SetField toValue(Object value) { + return new SetField(append("value", value)); + } + + @Override + protected String getMongoMethod() { + return "$setField"; + } + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java index 32e846966..b1641f5f6 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java @@ -233,6 +233,7 @@ public class MethodReferenceNode extends ExpressionNode { map.put("objectToArray", singleArgRef().forOperator("$objectToArray")); map.put("mergeObjects", arrayArgRef().forOperator("$mergeObjects")); map.put("getField", mapArgRef().forOperator("$getField").mappingParametersTo("field", "input")); + map.put("setField", mapArgRef().forOperator("$setField").mappingParametersTo("field", "value", "input")); // CONVERT OPERATORS map.put("convert", mapArgRef().forOperator("$convert") // diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ObjectOperatorsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ObjectOperatorsUnitTests.java index 1854a94fc..3ee7b08a4 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ObjectOperatorsUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ObjectOperatorsUnitTests.java @@ -109,4 +109,18 @@ public class ObjectOperatorsUnitTests { .isEqualTo(Document.parse("{ $getField : { field : \"robin\", input : \"$batman\" }}")); } + @Test // GH-4139 + public void setField() { + + assertThat(ObjectOperators.valueOf("batman").setField("friend").toValue("robin").toDocument(Aggregation.DEFAULT_CONTEXT)) + .isEqualTo(Document.parse("{ $setField : { field : \"friend\", value : \"robin\", input : \"$batman\" }}")); + } + + @Test // GH-4139 + public void removeField() { + + assertThat(ObjectOperators.valueOf("batman").removeField("joker").toDocument(Aggregation.DEFAULT_CONTEXT)) + .isEqualTo(Document.parse("{ $setField : { field : \"joker\", value : \"$$REMOVE\", input : \"$batman\" }}")); + } + } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java index 5f54bc5d1..e5dca5f36 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java @@ -1230,6 +1230,11 @@ public class SpelExpressionTransformerUnitTests { assertThat(transform("getField(\"score\", source)")).isEqualTo("{ $getField : { field : \"score\", input : \"$source\" }}"); } + @Test // GH-4139 + void shouldRenderSetField() { + assertThat(transform("setField(\"score\", 100, source)")).isEqualTo("{ $setField : { field : \"score\", value : 100, input : \"$source\" }}"); + } + private Document transform(String expression, Object... params) { return (Document) transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params); }