diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java index 81adc4035..5563c6850 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java @@ -267,6 +267,19 @@ public class ArrayOperators { return (usesFieldRef() ? In.arrayOf(fieldReference) : In.arrayOf(expression)).containsValue(value); } + /** + * Creates new {@link AggregationExpression} that converts the associated expression into an object. + * NOTE: Requires MongoDB 3.6 or later. + * + * @return new instance of {@link ArrayToObject}. + * @since 2.1 + */ + public ArrayToObject toObject() { + + return usesFieldRef() ? ArrayToObject.arrayValueOfToObject(fieldReference) + : ArrayToObject.arrayValueOfToObject(expression); + } + /** * @author Christoph Strobl */ @@ -1497,4 +1510,59 @@ public class ArrayOperators { In containsValue(Object value); } } + + /** + * {@link AggregationExpression} for {@code $arrayToObject} that transforms an array into a single document.
+ * NOTE: Requires MongoDB 3.6 or later. + * + * @author Christoph Strobl + * @see https://docs.mongodb.com/manual/reference/operator/aggregation/arrayToObject/ + * @since 2.1 + */ + public static class ArrayToObject extends AbstractAggregationExpression { + + private ArrayToObject(Object value) { + super(value); + } + + /** + * Converts the given array (e.g. an array of two-element arrays, a field reference to an array,...) to an object. + * + * @param array must not be {@literal null}. + * @return new instance of {@link ArrayToObject}. + */ + public static ArrayToObject arrayToObject(Object array) { + return new ArrayToObject(array); + } + + /** + * Converts the array pointed to by the given {@link Field field reference} to an object. + * + * @param fieldReference must not be {@literal null}. + * @return new instance of {@link ArrayToObject}. + */ + public static ArrayToObject arrayValueOfToObject(String fieldReference) { + return new ArrayToObject(Fields.field(fieldReference)); + } + + /** + * Converts the result array of the given {@link AggregationExpression expression} to an object. + * + * @param expression must not be {@literal null}. + * @return new instance of {@link ArrayToObject}. + */ + public static ArrayToObject arrayValueOfToObject(AggregationExpression expression) { + return new ArrayToObject(expression); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.aggregation.AbstractAggregationExpression#getMongoMethod() + */ + @Override + protected String getMongoMethod() { + return "$arrayToObject"; + } + } } 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 17a7bcdab..d9f68a1e5 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 @@ -113,6 +113,17 @@ public class ObjectOperators { public MergeObjects mergeWithValuesOf(AggregationExpression... expression) { return merge().mergeWithValuesOf(expression); } + + /** + * Creates new {@link ObjectToArray aggregation expression} that takes the associated value and converts it to an + * array of {@link Document documents} that contain two fields {@literal k} and {@literal v} each.
+ * NOTE: Requires MongoDB 3.6 or later. + * + * @since 2.1 + */ + public ObjectToArray toArray() { + return ObjectToArray.toArray(value); + } } /** @@ -226,4 +237,62 @@ public class ObjectOperators { return "$mergeObjects"; } } + + /** + * {@link AggregationExpression} for {@code $objectToArray} that converts a document to an array of {@link Document + * documents} that each contains two fields {@literal k} and {@literal v}.
+ * NOTE: Requires MongoDB 3.6 or later. + * + * @author Christoph Strobl + * @see https://docs.mongodb.com/manual/reference/operator/aggregation/objectToArray/ + * @since 2.1 + */ + public static class ObjectToArray extends AbstractAggregationExpression { + + private ObjectToArray(Object value) { + super(value); + } + + /** + * Creates new {@link ObjectToArray aggregation expression} that takes the value pointed to by given {@link Field + * fieldReference} and converts it to an array. + * + * @param fieldReference must not be {@literal null}. + * @return new instance of {@link ObjectToArray}. + */ + public static ObjectToArray valueOfToArray(String fieldReference) { + return toArray(Fields.field(fieldReference)); + } + + /** + * Creates new {@link ObjectToArray aggregation expression} that takes the result value of the given + * {@link AggregationExpression expression} and converts it to an array. + * + * @param expression must not be {@literal null}. + * @return new instance of {@link ObjectToArray}. + */ + public static ObjectToArray valueOfToArray(AggregationExpression expression) { + return toArray(expression); + } + + /** + * Creates new {@link ObjectToArray aggregation expression} that takes the given value and converts it to an array. + * + * @param value must not be {@literal null}. + * @return new instance of {@link ObjectToArray}. + */ + public static ObjectToArray toArray(Object value) { + return new ObjectToArray(value); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.aggregation.AbstractAggregationExpression#getMongoMethod() + */ + @Override + protected String getMongoMethod() { + return "$objectToArray"; + } + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ArrayOperatorsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ArrayOperatorsUnitTests.java new file mode 100644 index 000000000..c0c777b3f --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ArrayOperatorsUnitTests.java @@ -0,0 +1,64 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.core.aggregation; + +import static org.assertj.core.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.bson.Document; +import org.junit.Test; +import org.springframework.data.mongodb.core.aggregation.ArrayOperators.ArrayToObject; + +/** + * Unit tests for {@link ArrayOperators} + * + * @author Christoph Strobl + * @currentRead Royal Assassin - Robin Hobb + */ +public class ArrayOperatorsUnitTests { + + static final String EXPRESSION_STRING = "{ \"$stablemaster\" : \"burrich\" }"; + static final Document EXPRESSION_DOC = Document.parse(EXPRESSION_STRING); + static final AggregationExpression EXPRESSION = context -> EXPRESSION_DOC; + + @Test // DATAMONGO-2052 + public void toArrayWithFieldReference() { + + assertThat(ArrayOperators.arrayOf("regal").toObject().toDocument(Aggregation.DEFAULT_CONTEXT)) + .isEqualTo(Document.parse("{ $arrayToObject: \"$regal\" } ")); + } + + @Test // DATAMONGO-2052 + public void toArrayWithExpression() { + + assertThat(ArrayOperators.arrayOf(EXPRESSION).toObject().toDocument(Aggregation.DEFAULT_CONTEXT)) + .isEqualTo(Document.parse("{ $arrayToObject: " + EXPRESSION_STRING + "} ")); + } + + @Test // DATAMONGO-2052 + public void toArrayWithArgumentList() { + + List> source = new ArrayList<>(); + source.add(Arrays.asList("king", "shrewd")); + source.add(Arrays.asList("prince", "verity")); + + assertThat(ArrayToObject.arrayToObject(source).toDocument(Aggregation.DEFAULT_CONTEXT)) + .isEqualTo(Document.parse("{ $arrayToObject: [ [ \"king\", \"shrewd\"], [ \"prince\", \"verity\" ] ] } ")); + } +} 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 a1b2a04b3..3d5088a4e 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 @@ -90,4 +90,18 @@ public class ObjectOperatorsUnitTests { "{ $mergeObjects: [ \"$kettricken\", " + EXPRESSION_STRING + ", { \"fitz\" : \"chivalry\" } ] } ")); } + @Test // DATAMONGO-2052 + public void toArrayWithFieldReference() { + + assertThat(ObjectOperators.valueOf("verity").toArray().toDocument(Aggregation.DEFAULT_CONTEXT)) + .isEqualTo(Document.parse("{ $objectToArray : \"$verity\" }")); + } + + @Test // DATAMONGO-2052 + public void toArrayWithExpression() { + + assertThat(ObjectOperators.valueOf(EXPRESSION).toArray().toDocument(Aggregation.DEFAULT_CONTEXT)) + .isEqualTo(Document.parse("{ $objectToArray : " + EXPRESSION_STRING + " }")); + } + } diff --git a/src/main/asciidoc/reference/mongodb.adoc b/src/main/asciidoc/reference/mongodb.adoc index 41735e475..18ae88aa2 100644 --- a/src/main/asciidoc/reference/mongodb.adoc +++ b/src/main/asciidoc/reference/mongodb.adoc @@ -2128,7 +2128,7 @@ At the time of this writing, we provide support for the following Aggregation Op | `eq` (*via: `is`), `gt`, `gte`, `lt`, `lte`, `ne` | Array Aggregation Operators -| `arrayElementAt`, `concatArrays`, `filter`, `in`, `indexOfArray`, `isArray`, `range`, `reverseArray`, `reduce`, `size`, `slice`, `zip` +| `arrayElementAt`, `arrayToObject`, `concatArrays`, `filter`, `in`, `indexOfArray`, `isArray`, `range`, `reverseArray`, `reduce`, `size`, `slice`, `zip` | Literal Operators | `literal` @@ -2149,7 +2149,7 @@ At the time of this writing, we provide support for the following Aggregation Op | `convert`, `toBool`, `toDate`, `toDecimal`, `toDouble`, `toInt`, `toLong`, `toObjectId`, `toString` | Object Aggregation Operators -| `mergeObjects` +| `objectToArray`, `mergeObjects` |=== * The operation is mapped or added by Spring Data MongoDB.