DATAMONGO-1548 - Add support for MongoDB 3.4 aggregation operators.

We now support the following MongoDB 3.4 aggregation operators:

$indexOfBytes, $indexOfCP, $split, $strLenBytes, $strLenCP, $substrCP, $indexOfArray, $range, $reverseArray, $reduce, $zip, $in, $isoDayOfWeek, $isoWeek, $isoWeekYear, $switch and $type.

Original pull request: #423.
This commit is contained in:
Christoph Strobl
2016-12-06 20:15:45 +01:00
committed by Mark Paluch
parent 3d8b6868c7
commit 0449719a16
8 changed files with 1975 additions and 13 deletions

View File

@@ -22,6 +22,7 @@ import java.util.Iterator;
import java.util.List;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
import org.springframework.util.Assert;
import org.springframework.util.CompositeIterator;
import org.springframework.util.ObjectUtils;
@@ -406,6 +407,11 @@ public final class ExposedFields implements Iterable<ExposedField> {
*/
@Override
public String toString() {
if(getRaw().startsWith("$")) {
return getRaw();
}
return String.format("$%s", getRaw());
}

View File

@@ -187,13 +187,13 @@ public final class Fields implements Iterable<Field> {
}
/**
*
* @return
* @since 1.10
*/
public List<Field> asList() {
return Collections.unmodifiableList(fields);
}
/**
* Value object to encapsulate a field in an aggregation operation.
*
@@ -201,6 +201,7 @@ public final class Fields implements Iterable<Field> {
*/
static class AggregationField implements Field {
private final String raw;
private final String name;
private final String target;
@@ -225,6 +226,7 @@ public final class Fields implements Iterable<Field> {
*/
public AggregationField(String name, String target) {
raw = name;
String nameToSet = cleanUp(name);
String targetToSet = cleanUp(target);
@@ -266,6 +268,11 @@ public final class Fields implements Iterable<Field> {
* @see org.springframework.data.mongodb.core.aggregation.Field#getAlias()
*/
public String getTarget() {
if (isLocalVar()) {
return this.getRaw();
}
return StringUtils.hasText(this.target) ? this.target : this.name;
}
@@ -278,6 +285,22 @@ public final class Fields implements Iterable<Field> {
return !getName().equals(getTarget());
}
/**
* @return {@literal true} in case the field name starts with {@code $$}.
* @since 1.10
*/
public boolean isLocalVar() {
return raw.startsWith("$$") && !raw.startsWith("$$$");
}
/**
* @return
* @since 1.10
*/
public String getRaw() {
return raw;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()

View File

@@ -491,8 +491,10 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer {
} else if (ObjectUtils.nullSafeEquals(methodReference.getArgumentType(), ArgumentType.MAP)) {
DBObject dbo = new BasicDBObject();
for (int i = 0; i < methodReference.getArgumentMap().length; i++) {
dbo.put(methodReference.getArgumentMap()[i], transform(node.getChild(i), context));
int i = 0;
for(ExpressionNode child : node) {
dbo.put(methodReference.getArgumentMap()[i++], transform(child, context));
}
args = dbo;
} else {

View File

@@ -90,6 +90,12 @@ public class MethodReferenceNode extends ExpressionNode {
map.put("toLower", singleArgumentAggregationMethodReference().forOperator("$toLower"));
map.put("toUpper", singleArgumentAggregationMethodReference().forOperator("$toUpper"));
map.put("strcasecmp", arrayArgumentAggregationMethodReference().forOperator("$strcasecmp"));
map.put("indexOfBytes", arrayArgumentAggregationMethodReference().forOperator("$indexOfBytes"));
map.put("indexOfCP", arrayArgumentAggregationMethodReference().forOperator("$indexOfCP"));
map.put("split", arrayArgumentAggregationMethodReference().forOperator("$split"));
map.put("strLenBytes", singleArgumentAggregationMethodReference().forOperator("$strLenBytes"));
map.put("strLenCP", singleArgumentAggregationMethodReference().forOperator("$strLenCP"));
map.put("substrCP", arrayArgumentAggregationMethodReference().forOperator("$substrCP"));
// TEXT SEARCH OPERATORS
map.put("meta", singleArgumentAggregationMethodReference().forOperator("$meta"));
@@ -102,6 +108,12 @@ public class MethodReferenceNode extends ExpressionNode {
map.put("isArray", singleArgumentAggregationMethodReference().forOperator("$isArray"));
map.put("size", singleArgumentAggregationMethodReference().forOperator("$size"));
map.put("slice", arrayArgumentAggregationMethodReference().forOperator("$slice"));
map.put("reverseArray", singleArgumentAggregationMethodReference().forOperator("$reverseArray"));
map.put("reduce", mapArgumentAggregationMethodReference().forOperator("$reduce").mappingParametersTo("input",
"initialValue", "in"));
map.put("zip", mapArgumentAggregationMethodReference().forOperator("$zip").mappingParametersTo("inputs",
"useLongestLength", "defaults"));
map.put("in", arrayArgumentAggregationMethodReference().forOperator("$in"));
// VARIABLE OPERATORS
map.put("map", mapArgumentAggregationMethodReference().forOperator("$map") //
@@ -124,6 +136,9 @@ public class MethodReferenceNode extends ExpressionNode {
map.put("millisecond", singleArgumentAggregationMethodReference().forOperator("$millisecond"));
map.put("dateToString", mapArgumentAggregationMethodReference().forOperator("$dateToString") //
.mappingParametersTo("format", "date"));
map.put("isoDayOfWeek", singleArgumentAggregationMethodReference().forOperator("$isoDayOfWeek"));
map.put("isoWeek", singleArgumentAggregationMethodReference().forOperator("$isoWeek"));
map.put("isoWeekYear", singleArgumentAggregationMethodReference().forOperator("$isoWeekYear"));
// CONDITIONAL OPERATORS
map.put("cond", mapArgumentAggregationMethodReference().forOperator("$cond") //
@@ -142,6 +157,9 @@ public class MethodReferenceNode extends ExpressionNode {
map.put("stdDevPop", arrayArgumentAggregationMethodReference().forOperator("$stdDevPop"));
map.put("stdDevSamp", arrayArgumentAggregationMethodReference().forOperator("$stdDevSamp"));
// TYPE OPERATORS
map.put("type", singleArgumentAggregationMethodReference().forOperator("$type"));
FUNCTIONS = Collections.unmodifiableMap(map);
}

View File

@@ -28,13 +28,35 @@ import static org.springframework.data.mongodb.util.DBObjectUtils.*;
import java.util.Arrays;
import java.util.List;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.springframework.data.domain.Range;
import org.springframework.data.mongodb.core.DBObjectTestUtils;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.And;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.ArithmeticOperators;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.ArrayOperators;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Avg;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.BooleanOperators;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.ComparisonOperators;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.ConditionalOperators;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.DateOperators;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Gte;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Let.ExpressionVariable;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.LiteralOperators;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Lt;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.RangeOperator;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Reduce.PropertyExpression;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Reduce.Variable;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.SetOperators;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.StringOperators;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Switch.CaseOperator;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Type;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.VariableOperators;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.*;
import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;
@@ -1792,7 +1814,296 @@ public class ProjectionOperationUnitTests {
"}}}}")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderIndexOfBytesCorrectly() {
DBObject agg = project().and(StringOperators.valueOf("item").indexOf("foo")).as("byteLocation")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project: { byteLocation: { $indexOfBytes: [ \"$item\", \"foo\" ] } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderIndexOfBytesWithRangeCorrectly() {
DBObject agg = project().and(StringOperators.valueOf("item").indexOf("foo").within(new Range<Long>(5L, 9L)))
.as("byteLocation").toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, isBsonObject().containing("$project.byteLocation.$indexOfBytes.[2]", 5L)
.containing("$project.byteLocation.$indexOfBytes.[3]", 9L));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderIndexOfCPCorrectly() {
DBObject agg = project().and(StringOperators.valueOf("item").indexOfCP("foo")).as("cpLocation")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project: { cpLocation: { $indexOfCP: [ \"$item\", \"foo\" ] } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderIndexOfCPWithRangeCorrectly() {
DBObject agg = project().and(StringOperators.valueOf("item").indexOfCP("foo").within(new Range<Long>(5L, 9L)))
.as("cpLocation").toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, isBsonObject().containing("$project.cpLocation.$indexOfCP.[2]", 5L)
.containing("$project.cpLocation.$indexOfCP.[3]", 9L));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderSplitCorrectly() {
DBObject agg = project().and(StringOperators.valueOf("city").split(", ")).as("city_state")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project : { city_state : { $split: [\"$city\", \", \"] }} }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderStrLenBytesCorrectly() {
DBObject agg = project().and(StringOperators.valueOf("name").length()).as("length")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project : { \"length\": { $strLenBytes: \"$name\" } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderStrLenCPCorrectly() {
DBObject agg = project().and(StringOperators.valueOf("name").lengthCP()).as("length")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project : { \"length\": { $strLenCP: \"$name\" } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderSubstrCPCorrectly() {
DBObject agg = project().and(StringOperators.valueOf("quarter").substringCP(0, 2)).as("yearSubstring")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project : { yearSubstring: { $substrCP: [ \"$quarter\", 0, 2 ] } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderIndexOfArrayCorrectly() {
DBObject agg = project().and(ArrayOperators.arrayOf("items").indexOf(2)).as("index")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project : { index: { $indexOfArray: [ \"$items\", 2 ] } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderRangeCorrectly() {
DBObject agg = project().and(RangeOperator.rangeStartingAt(0L).to("distance").withStepSize(25L)).as("rest_stops")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, isBsonObject().containing("$project.rest_stops.$range.[0]", 0L)
.containing("$project.rest_stops.$range.[1]", "$distance").containing("$project.rest_stops.$range.[2]", 25L));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderReverseArrayCorrectly() {
DBObject agg = project().and(ArrayOperators.arrayOf("favorites").reverse()).as("reverseFavorites")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project : { reverseFavorites: { $reverseArray: \"$favorites\" } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderReduceWithSimpleObjectCorrectly() {
DBObject agg = project()
.and(ArrayOperators.arrayOf("probabilityArr")
.reduce(ArithmeticOperators.valueOf("$$value").multiplyBy("$$this")).startingWith(1))
.as("results").toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse(
"{ $project : { \"results\": { $reduce: { input: \"$probabilityArr\", initialValue: 1, in: { $multiply: [ \"$$value\", \"$$this\" ] } } } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderReduceWithComplexObjectCorrectly() {
PropertyExpression sum = PropertyExpression.property("sum").definedAs(
ArithmeticOperators.valueOf(Variable.VALUE.referingTo("sum").getName()).add(Variable.THIS.getName()));
PropertyExpression product = PropertyExpression.property("product").definedAs(ArithmeticOperators
.valueOf(Variable.VALUE.referingTo("product").getName()).multiplyBy(Variable.THIS.getName()));
DBObject agg = project()
.and(ArrayOperators.arrayOf("probabilityArr").reduce(sum, product)
.startingWith(new BasicDBObjectBuilder().add("sum", 5).add("product", 2).get()))
.as("results").toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse(
"{ $project : { \"results\": { $reduce: { input: \"$probabilityArr\", initialValue: { \"sum\" : 5 , \"product\" : 2} , in: { \"sum\": { $add : [\"$$value.sum\", \"$$this\"] }, \"product\": { $multiply: [ \"$$value.product\", \"$$this\" ] } } } } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderZipCorrectly() {
AggregationExpression elemAt0 = ArrayOperators.arrayOf("matrix").elementAt(0);
AggregationExpression elemAt1 = ArrayOperators.arrayOf("matrix").elementAt(1);
AggregationExpression elemAt2 = ArrayOperators.arrayOf("matrix").elementAt(2);
DBObject agg = project().and(
ArrayOperators.arrayOf(elemAt0).zipWith(elemAt1, elemAt2).useLongestLength().defaultTo(new Object[] { 1, 2 }))
.as("transposed").toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse(
"{ $project : { transposed: { $zip: { inputs: [ { $arrayElemAt: [ \"$matrix\", 0 ] }, { $arrayElemAt: [ \"$matrix\", 1 ] }, { $arrayElemAt: [ \"$matrix\", 2 ] } ], useLongestLength : true, defaults: [1,2] } } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderInCorrectly() {
DBObject agg = project().and(ArrayOperators.arrayOf("in_stock").containsValue("bananas")).as("has_bananas")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project : { has_bananas : { $in : [\"bananas\", \"$in_stock\" ] } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderIsoDayOfWeekCorrectly() {
DBObject agg = project().and(DateOperators.dateOf("birthday").isoDayOfWeek()).as("dayOfWeek")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project : { dayOfWeek: { $isoDayOfWeek: \"$birthday\" } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderIsoWeekCorrectly() {
DBObject agg = project().and(DateOperators.dateOf("date").isoWeek()).as("weekNumber")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project : { weekNumber: { $isoWeek: \"$date\" } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderIsoWeekYearCorrectly() {
DBObject agg = project().and(DateOperators.dateOf("date").isoWeekYear()).as("yearNumber")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project : { yearNumber: { $isoWeekYear: \"$date\" } } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderSwitchCorrectly() {
String expected = "$switch:\n" + //
"{\n" + //
" branches: [\n" + //
" {\n" + //
" case: { $gte : [ { $avg : \"$scores\" }, 90 ] },\n" + //
" then: \"Doing great!\"\n" + //
" },\n" + //
" {\n" + //
" case: { $and : [ { $gte : [ { $avg : \"$scores\" }, 80 ] },\n" + //
" { $lt : [ { $avg : \"$scores\" }, 90 ] } ] },\n" + //
" then: \"Doing pretty well.\"\n" + //
" },\n" + //
" {\n" + //
" case: { $lt : [ { $avg : \"$scores\" }, 80 ] },\n" + //
" then: \"Needs improvement.\"\n" + //
" }\n" + //
" ],\n" + //
" default: \"No scores found.\"\n" + //
" }\n" + //
"}";
CaseOperator cond1 = CaseOperator.when(Gte.valueOf(Avg.avgOf("scores")).greaterThanEqualToValue(90))
.then("Doing great!");
CaseOperator cond2 = CaseOperator.when(And.and(Gte.valueOf(Avg.avgOf("scores")).greaterThanEqualToValue(80),
Lt.valueOf(Avg.avgOf("scores")).lessThanValue(90))).then("Doing pretty well.");
CaseOperator cond3 = CaseOperator.when(Lt.valueOf(Avg.avgOf("scores")).lessThanValue(80))
.then("Needs improvement.");
DBObject agg = project().and(ConditionalOperators.switchCases(cond1, cond2, cond3).defaultTo("No scores found."))
.as("summary").toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project : { summary: {" + expected + "} } }")));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldTypeCorrectly() {
DBObject agg = project().and(Type.typeOf("a")).as("a")
.toDBObject(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(JSON.parse("{ $project : { a: { $type: \"$a\" } } }")));
}
private static DBObject exctractOperation(String field, DBObject fromProjectClause) {
return (DBObject) fromProjectClause.get(field);
}
}

View File

@@ -745,13 +745,13 @@ public class SpelExpressionTransformerUnitTests {
assertThat(transform("min(a, b)"), is("{ \"$min\" : [ \"$a\" , \"$b\"]}"));
}
/**
* @see DATAMONGO-1530
*/
@Test
public void shouldRenderMethodReferenceNodePush() {
assertThat(transform("push({'item':'$item', 'quantity':'$qty'})"), is("{ \"$push\" : { \"item\" : \"$item\" , \"quantity\" : \"$qty\"}}"));
assertThat(transform("push({'item':'$item', 'quantity':'$qty'})"),
is("{ \"$push\" : { \"item\" : \"$item\" , \"quantity\" : \"$qty\"}}"));
}
/**
@@ -884,6 +884,129 @@ public class SpelExpressionTransformerUnitTests {
assertThat(transform("!(foo > 10)"), is("{ \"$not\" : [ { \"$gt\" : [ \"$foo\" , 10]}]}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodReferenceIndexOfBytes() {
assertThat(transform("indexOfBytes(item, 'foo')"), is("{ \"$indexOfBytes\" : [ \"$item\" , \"foo\"]}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodReferenceIndexOfCP() {
assertThat(transform("indexOfCP(item, 'foo')"), is("{ \"$indexOfCP\" : [ \"$item\" , \"foo\"]}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodReferenceSplit() {
assertThat(transform("split(item, ',')"), is("{ \"$split\" : [ \"$item\" , \",\"]}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodReferenceStrLenBytes() {
assertThat(transform("strLenBytes(item)"), is("{ \"$strLenBytes\" : \"$item\"}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodReferenceStrLenCP() {
assertThat(transform("strLenCP(item)"), is("{ \"$strLenCP\" : \"$item\"}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodSubstrCP() {
assertThat(transform("substrCP(item, 0, 5)"), is("{ \"$substrCP\" : [ \"$item\" , 0 , 5]}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodReferenceReverseArray() {
assertThat(transform("reverseArray(array)"), is("{ \"$reverseArray\" : \"$array\"}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodReferenceReduce() {
assertThat(transform("reduce(field, '', {'$concat':new String[]{'$$value','$$this'}})"), is(
"{ \"$reduce\" : { \"input\" : \"$field\" , \"initialValue\" : \"\" , \"in\" : { \"$concat\" : [ \"$$value\" , \"$$this\"]}}}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodReferenceZip() {
assertThat(transform("zip(new String[]{'$array1', '$array2'})"),
is("{ \"$zip\" : { \"inputs\" : [ \"$array1\" , \"$array2\"]}}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodReferenceZipWithOptionalArgs() {
assertThat(transform("zip(new String[]{'$array1', '$array2'}, true, new int[]{1,2})"), is(
"{ \"$zip\" : { \"inputs\" : [ \"$array1\" , \"$array2\"] , \"useLongestLength\" : true , \"defaults\" : [ 1 , 2]}}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodIn() {
assertThat(transform("in('item', array)"), is("{ \"$in\" : [ \"item\" , \"$array\"]}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodRefereneIsoDayOfWeek() {
assertThat(transform("isoDayOfWeek(date)"), is("{ \"$isoDayOfWeek\" : \"$date\"}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodRefereneIsoWeek() {
assertThat(transform("isoWeek(date)"), is("{ \"$isoWeek\" : \"$date\"}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodRefereneIsoWeekYear() {
assertThat(transform("isoWeekYear(date)"), is("{ \"$isoWeekYear\" : \"$date\"}"));
}
/**
* @see DATAMONGO-1548
*/
@Test
public void shouldRenderMethodRefereneType() {
assertThat(transform("type(a)"), is("{ \"$type\" : \"$a\"}"));
}
private String transform(String expression, Object... params) {
Object result = transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params);
return result == null ? null : result.toString();

View File

@@ -1686,26 +1686,28 @@ At the time of this writing we provide support for the following Aggregation Ope
| 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
| concat, substr, toLower, toUpper, stcasecmp, indexOfBytes, indexOfCP, split, strLenBytes, strLenCP, substrCP,
| Comparison Aggregation Operators
| eq (*via: is), gt, gte, lt, lte, ne
| Array Aggregation Operators
| arrayElementAt, concatArrays, filter, isArray, size, slice
| arrayElementAt, concatArrays, filter, in, indexOfArray, isArray, range, reverseArray, reduce, size, slice, zip
| Literal Operators
| literal
| Date Aggregation Operators
| dayOfYear, dayOfMonth, dayOfWeek, year, month, week, hour, minute, second, millisecond, dateToString
| dayOfYear, dayOfMonth, dayOfWeek, year, month, week, hour, minute, second, millisecond, dateToString, isoDayOfWeek, isoWeek, isoWeekYear
| Variable Operators
| map
| Conditional Aggregation Operators
| cond, ifNull
| cond, ifNull, switch
| Type Aggregation Operators
| type
|===