diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/StringOperators.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/StringOperators.java
index 17349ec29..6e431671a 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/StringOperators.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/StringOperators.java
@@ -350,8 +350,7 @@ public class StringOperators {
* @return
*/
public StrLenBytes length() {
- return usesFieldRef() ? StrLenBytes.stringLengthOf(fieldReference)
- : StrLenBytes.stringLengthOf(expression);
+ return usesFieldRef() ? StrLenBytes.stringLengthOf(fieldReference) : StrLenBytes.stringLengthOf(expression);
}
/**
@@ -391,6 +390,132 @@ public class StringOperators {
return usesFieldRef() ? SubstrCP.valueOf(fieldReference) : SubstrCP.valueOf(expression);
}
+ /**
+ * Creates new {@link AggregationExpression} that takes the associated string representation and trims whitespaces
+ * from the beginning and end.
+ * NOTE: Requires MongoDB 4.0 or later.
+ *
+ * @return new instance of {@link Trim}.
+ * @since 2.1
+ */
+ public Trim trim() {
+ return createTrim();
+ }
+
+ /**
+ * Creates new {@link AggregationExpression} that takes the associated string representation and trims the given
+ * character sequence from the beginning and end.
+ * NOTE: Requires MongoDB 4.0 or later.
+ *
+ * @param chars must not be {@literal null}.
+ * @return new instance of {@link Trim}.
+ * @since 2.1
+ */
+ public Trim trim(String chars) {
+ return trim().chars(chars);
+ }
+
+ /**
+ * Creates new {@link AggregationExpression} that takes the associated string representation and trims the character
+ * sequence resulting from the given {@link AggregationExpression} from the beginning and end.
+ * NOTE: Requires MongoDB 4.0 or later.
+ *
+ * @param expression must not be {@literal null}.
+ * @return new instance of {@link Trim}.
+ * @since 2.1
+ */
+ public Trim trim(AggregationExpression expression) {
+ return trim().charsOf(expression);
+ }
+
+ private Trim createTrim() {
+ return usesFieldRef() ? Trim.valueOf(fieldReference) : Trim.valueOf(expression);
+ }
+
+ /**
+ * Creates new {@link AggregationExpression} that takes the associated string representation and trims whitespaces
+ * from the beginning.
+ * NOTE: Requires MongoDB 4.0 or later.
+ *
+ * @return new instance of {@link LTrim}.
+ * @since 2.1
+ */
+ public LTrim ltrim() {
+ return createLTrim();
+ }
+
+ /**
+ * Creates new {@link AggregationExpression} that takes the associated string representation and trims the given
+ * character sequence from the beginning.
+ * NOTE: Requires MongoDB 4.0 or later.
+ *
+ * @param chars must not be {@literal null}.
+ * @return new instance of {@link LTrim}.
+ * @since 2.1
+ */
+ public LTrim ltrim(String chars) {
+ return ltrim().chars(chars);
+ }
+
+ /**
+ * Creates new {@link AggregationExpression} that takes the associated string representation and trims the character
+ * sequence resulting from the given {@link AggregationExpression} from the beginning.
+ * NOTE: Requires MongoDB 4.0 or later.
+ *
+ * @param expression must not be {@literal null}.
+ * @return new instance of {@link LTrim}.
+ * @since 2.1
+ */
+ public LTrim ltrim(AggregationExpression expression) {
+ return ltrim().charsOf(expression);
+ }
+
+ private LTrim createLTrim() {
+ return usesFieldRef() ? LTrim.valueOf(fieldReference) : LTrim.valueOf(expression);
+ }
+
+ /**
+ * Creates new {@link AggregationExpression} that takes the associated string representation and trims whitespaces
+ * from the end.
+ * NOTE: Requires MongoDB 4.0 or later.
+ *
+ * @return new instance of {@link RTrim}.
+ * @since 2.1
+ */
+ public RTrim rtrim() {
+ return createRTrim();
+ }
+
+ /**
+ * Creates new {@link AggregationExpression} that takes the associated string representation and trims the given
+ * character sequence from the end.
+ * NOTE: Requires MongoDB 4.0 or later.
+ *
+ * @param chars must not be {@literal null}.
+ * @return new instance of {@link RTrim}.
+ * @since 2.1
+ */
+ public RTrim rtrim(String chars) {
+ return rtrim().chars(chars);
+ }
+
+ /**
+ * Creates new {@link AggregationExpression} that takes the associated string representation and trims the character
+ * sequence resulting from the given {@link AggregationExpression} from the end.
+ * NOTE: Requires MongoDB 4.0 or later.
+ *
+ * @param expression must not be {@literal null}.
+ * @return new instance of {@link RTrim}.
+ * @since 2.1
+ */
+ public RTrim rtrim(AggregationExpression expression) {
+ return rtrim().charsOf(expression);
+ }
+
+ private RTrim createRTrim() {
+ return usesFieldRef() ? RTrim.valueOf(fieldReference) : RTrim.valueOf(expression);
+ }
+
private boolean usesFieldRef() {
return fieldReference != null;
}
@@ -1072,4 +1197,257 @@ public class StringOperators {
return new SubstrCP(append(Arrays.asList(start, nrOfChars)));
}
}
+
+ /**
+ * {@link AggregationExpression} for {@code $trim} which removes whitespace or the specified characters from the
+ * beginning and end of a string.
+ * NOTE: Requires MongoDB 4.0 or later.
+ *
+ * @author Christoph Strobl
+ * @since 2.1
+ */
+ public static class Trim extends AbstractAggregationExpression {
+
+ private Trim(Object value) {
+ super(value);
+ }
+
+ /**
+ * Creates new {@link Trim} using the value of the provided {@link Field fieldReference} as {@literal input} value.
+ *
+ * @param fieldReference must not be {@literal null}.
+ * @return new instance of {@link LTrim}.
+ */
+ public static Trim valueOf(String fieldReference) {
+
+ Assert.notNull(fieldReference, "FieldReference must not be null!");
+ return new Trim(Collections.singletonMap("input", Fields.field(fieldReference)));
+ }
+
+ /**
+ * Creates new {@link Trim} using the result of the provided {@link AggregationExpression} as {@literal input}
+ * value.
+ *
+ * @param expression must not be {@literal null}.
+ * @return new instance of {@link Trim}.
+ */
+ public static Trim valueOf(AggregationExpression expression) {
+
+ Assert.notNull(expression, "Expression must not be null!");
+ return new Trim(Collections.singletonMap("input", expression));
+ }
+
+ /**
+ * Optional specify the character(s) to trim from the beginning.
+ *
+ * @param chars must not be {@literal null}.
+ * @return new instance of {@link Trim}.
+ */
+ public Trim chars(String chars) {
+
+ Assert.notNull(chars, "Chars must not be null!");
+ return new Trim(append("chars", chars));
+ }
+
+ /**
+ * Optional specify the reference to the {@link Field field} holding the character values to trim from the
+ * beginning.
+ *
+ * @param fieldReference must not be {@literal null}.
+ * @return new instance of {@link Trim}.
+ */
+ public Trim charsOf(String fieldReference) {
+ return new Trim(append("chars", Fields.field(fieldReference)));
+ }
+
+ /**
+ * Optional specify the {@link AggregationExpression} evaluating to the character sequence to trim from the
+ * beginning.
+ *
+ * @param expression must not be {@literal null}.
+ * @return new instance of {@link Trim}.
+ */
+ public Trim charsOf(AggregationExpression expression) {
+ return new Trim(append("chars", expression));
+ }
+
+ /**
+ * Remove whitespace or the specified characters from the beginning of a string.
+ *
+ * @return new instance of {@link LTrim}.
+ */
+ public LTrim left() {
+ return new LTrim(argumentMap());
+ }
+
+ /**
+ * Remove whitespace or the specified characters from the end of a string.
+ *
+ * @return new instance of {@link RTrim}.
+ */
+ public RTrim right() {
+ return new RTrim(argumentMap());
+ }
+
+ @Override
+ protected String getMongoMethod() {
+ return "$trim";
+ }
+ }
+
+ /**
+ * {@link AggregationExpression} for {@code $ltrim} which removes whitespace or the specified characters from the
+ * beginning of a string.
+ * NOTE: Requires MongoDB 4.0 or later.
+ *
+ * @author Christoph Strobl
+ * @since 2.1
+ */
+ public static class LTrim extends AbstractAggregationExpression {
+
+ private LTrim(Object value) {
+ super(value);
+ }
+
+ /**
+ * Creates new {@link LTrim} using the value of the provided {@link Field fieldReference} as {@literal input} value.
+ *
+ * @param fieldReference must not be {@literal null}.
+ * @return new instance of {@link LTrim}.
+ */
+ public static LTrim valueOf(String fieldReference) {
+
+ Assert.notNull(fieldReference, "FieldReference must not be null!");
+ return new LTrim(Collections.singletonMap("input", Fields.field(fieldReference)));
+ }
+
+ /**
+ * Creates new {@link LTrim} using the result of the provided {@link AggregationExpression} as {@literal input}
+ * value.
+ *
+ * @param expression must not be {@literal null}.
+ * @return new instance of {@link LTrim}.
+ */
+ public static LTrim valueOf(AggregationExpression expression) {
+
+ Assert.notNull(expression, "Expression must not be null!");
+ return new LTrim(Collections.singletonMap("input", expression));
+ }
+
+ /**
+ * Optional specify the character(s) to trim from the beginning.
+ *
+ * @param chars must not be {@literal null}.
+ * @return new instance of {@link LTrim}.
+ */
+ public LTrim chars(String chars) {
+
+ Assert.notNull(chars, "Chars must not be null!");
+ return new LTrim(append("chars", chars));
+ }
+
+ /**
+ * Optional specify the reference to the {@link Field field} holding the character values to trim from the
+ * beginning.
+ *
+ * @param fieldReference must not be {@literal null}.
+ * @return new instance of {@link LTrim}.
+ */
+ public LTrim charsOf(String fieldReference) {
+ return new LTrim(append("chars", Fields.field(fieldReference)));
+ }
+
+ /**
+ * Optional specify the {@link AggregationExpression} evaluating to the character sequence to trim from the
+ * beginning.
+ *
+ * @param expression must not be {@literal null}.
+ * @return new instance of {@link LTrim}.
+ */
+ public LTrim charsOf(AggregationExpression expression) {
+ return new LTrim(append("chars", expression));
+ }
+
+ @Override
+ protected String getMongoMethod() {
+ return "$ltrim";
+ }
+ }
+
+ /**
+ * {@link AggregationExpression} for {@code $rtrim} which removes whitespace or the specified characters from the end
+ * of a string.
+ * NOTE: Requires MongoDB 4.0 or later.
+ *
+ * @author Christoph Strobl
+ * @since 2.1
+ */
+ public static class RTrim extends AbstractAggregationExpression {
+
+ private RTrim(Object value) {
+ super(value);
+ }
+
+ /**
+ * Creates new {@link RTrim} using the value of the provided {@link Field fieldReference} as {@literal input} value.
+ *
+ * @param fieldReference must not be {@literal null}.
+ * @return new instance of {@link RTrim}.
+ */
+ public static RTrim valueOf(String fieldReference) {
+
+ Assert.notNull(fieldReference, "FieldReference must not be null!");
+ return new RTrim(Collections.singletonMap("input", Fields.field(fieldReference)));
+ }
+
+ /**
+ * Creates new {@link RTrim} using the result of the provided {@link AggregationExpression} as {@literal input}
+ * value.
+ *
+ * @param expression must not be {@literal null}.
+ * @return new instance of {@link RTrim}.
+ */
+ public static RTrim valueOf(AggregationExpression expression) {
+
+ Assert.notNull(expression, "Expression must not be null!");
+ return new RTrim(Collections.singletonMap("input", expression));
+ }
+
+ /**
+ * Optional specify the character(s) to trim from the end.
+ *
+ * @param chars must not be {@literal null}.
+ * @return new instance of {@link RTrim}.
+ */
+ public RTrim chars(String chars) {
+
+ Assert.notNull(chars, "Chars must not be null!");
+ return new RTrim(append("chars", chars));
+ }
+
+ /**
+ * Optional specify the reference to the {@link Field field} holding the character values to trim from the end.
+ *
+ * @param fieldReference must not be {@literal null}.
+ * @return new instance of {@link RTrim}.
+ */
+ public RTrim charsOf(String fieldReference) {
+ return new RTrim(append("chars", Fields.field(fieldReference)));
+ }
+
+ /**
+ * Optional specify the {@link AggregationExpression} evaluating to the character sequence to trim from the end.
+ *
+ * @param expression must not be {@literal null}.
+ * @return new instance of {@link RTrim}.
+ */
+ public RTrim charsOf(AggregationExpression expression) {
+ return new RTrim(append("chars", expression));
+ }
+
+ @Override
+ protected String getMongoMethod() {
+ return "$rtrim";
+ }
+ }
}
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/StringOperatorsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/StringOperatorsUnitTests.java
new file mode 100644
index 000000000..9bf7ff722
--- /dev/null
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/StringOperatorsUnitTests.java
@@ -0,0 +1,146 @@
+/*
+ * 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 org.assertj.core.api.Assertions;
+import org.bson.Document;
+import org.junit.Test;
+
+/**
+ * Unit test for {@link StringOperators}.
+ *
+ * @author Christoph Strobl
+ * @currentRead Royal Assassin - Robin Hobb
+ */
+public class StringOperatorsUnitTests {
+
+ static final String EXPRESSION_STRING = "{ \"$fitz\" : \"chivalry\" }";
+ static final Document EXPRESSION_DOC = Document.parse(EXPRESSION_STRING);
+ static final AggregationExpression EXPRESSION = context -> EXPRESSION_DOC;
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderTrim() {
+
+ Assertions.assertThat(StringOperators.valueOf("shrewd").trim().toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $trim: { \"input\" : \"$shrewd\" } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderTrimForExpression() {
+
+ Assertions.assertThat(StringOperators.valueOf(EXPRESSION).trim().toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $trim: { \"input\" : " + EXPRESSION_STRING + " } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderTrimWithChars() {
+
+ Assertions.assertThat(StringOperators.valueOf("shrewd").trim("sh").toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $trim: { \"input\" : \"$shrewd\", \"chars\" : \"sh\" } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderTrimWithCharsExpression() {
+
+ Assertions.assertThat(StringOperators.valueOf("shrewd").trim(EXPRESSION).toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $trim: { \"input\" : \"$shrewd\", \"chars\" : " + EXPRESSION_STRING + " } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderTrimLeft() {
+
+ Assertions.assertThat(StringOperators.valueOf("shrewd").trim().left().toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $ltrim: { \"input\" : \"$shrewd\" } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderTrimLeftWithChars() {
+
+ Assertions.assertThat(StringOperators.valueOf("shrewd").trim("sh").left().toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $ltrim: { \"input\" : \"$shrewd\", \"chars\" : \"sh\" } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderTrimRight() {
+
+ Assertions.assertThat(StringOperators.valueOf("shrewd").trim().right().toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $rtrim: { \"input\" : \"$shrewd\" } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderTrimRightWithChars() {
+
+ Assertions.assertThat(StringOperators.valueOf("shrewd").trim("sh").right().toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $rtrim: { \"input\" : \"$shrewd\", \"chars\" : \"sh\" } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderLTrim() {
+
+ Assertions.assertThat(StringOperators.valueOf("shrewd").ltrim().toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $ltrim: { \"input\" : \"$shrewd\" } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderLTrimForExpression() {
+
+ Assertions.assertThat(StringOperators.valueOf(EXPRESSION).ltrim().toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $ltrim: { \"input\" : " + EXPRESSION_STRING + " } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderLTrimWithChars() {
+
+ Assertions.assertThat(StringOperators.valueOf("shrewd").ltrim("sh").toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $ltrim: { \"input\" : \"$shrewd\", \"chars\" : \"sh\" } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderLTrimWithCharsExpression() {
+
+ Assertions.assertThat(StringOperators.valueOf("shrewd").ltrim(EXPRESSION).toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $ltrim: { \"input\" : \"$shrewd\", \"chars\" : " + EXPRESSION_STRING + " } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderRTrim() {
+
+ Assertions.assertThat(StringOperators.valueOf("shrewd").rtrim().toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $rtrim: { \"input\" : \"$shrewd\" } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderRTrimForExpression() {
+
+ Assertions.assertThat(StringOperators.valueOf(EXPRESSION).rtrim().toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $rtrim: { \"input\" : " + EXPRESSION_STRING + " } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderRTrimWithChars() {
+
+ Assertions.assertThat(StringOperators.valueOf("shrewd").rtrim("sh").toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $rtrim: { \"input\" : \"$shrewd\", \"chars\" : \"sh\" } } "));
+ }
+
+ @Test // DATAMONGO-2049
+ public void shouldRenderRTrimWithCharsExpression() {
+
+ Assertions.assertThat(StringOperators.valueOf("shrewd").rtrim(EXPRESSION).toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $rtrim: { \"input\" : \"$shrewd\", \"chars\" : " + EXPRESSION_STRING + " } } "));
+ }
+
+}
diff --git a/src/main/asciidoc/reference/mongodb.adoc b/src/main/asciidoc/reference/mongodb.adoc
index 33b20c9e8..6af4f5e44 100644
--- a/src/main/asciidoc/reference/mongodb.adoc
+++ b/src/main/asciidoc/reference/mongodb.adoc
@@ -2119,7 +2119,7 @@ At the time of this writing, we provide support for the following Aggregation Op
| `abs`, `add` (*via `plus`), `ceil`, `divide`, `exp`, `floor`, `ln`, `log`, `log10`, `mod`, `multiply`, `pow`, `sqrt`, `subtract` (*via `minus`), `trunc`
| String Aggregation Operators
-| `concat`, `substr`, `toLower`, `toUpper`, `stcasecmp`, `indexOfBytes`, `indexOfCP`, `split`, `strLenBytes`, `strLenCP`, `substrCP`
+| `concat`, `substr`, `toLower`, `toUpper`, `stcasecmp`, `indexOfBytes`, `indexOfCP`, `split`, `strLenBytes`, `strLenCP`, `substrCP`, `trim`, `ltrim`, `rtim`
| Comparison Aggregation Operators
| `eq` (*via: `is`), `gt`, `gte`, `lt`, `lte`, `ne`