Add support for $dateDiff aggregation operator.
Closes: #3713 Original pull request: #3748.
This commit is contained in:
committed by
Mark Paluch
parent
afef243634
commit
fc41793d5d
@@ -340,6 +340,42 @@ public class DateOperators {
|
||||
return applyTimezone(DayOfWeek.dayOfWeek(dateReference()), timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that calculates the difference (in {@literal units) to the date
|
||||
* computed by the given {@link AggregationExpression expression}. @param expression must not be {@literal null}.
|
||||
*
|
||||
* @param unit the unit of measure. Must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
* @since 3.3
|
||||
*/
|
||||
public DateDiff diffValueOf(AggregationExpression expression, String unit) {
|
||||
return applyTimezone(DateDiff.diffValueOf(expression, unit).toDate(dateReference()), timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that calculates the difference (in {@literal units) to the date stored
|
||||
* at the given {@literal field}. @param expression must not be {@literal null}.
|
||||
*
|
||||
* @param unit the unit of measure. Must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
* @since 3.3
|
||||
*/
|
||||
public DateDiff diffValueOf(String fieldReference, String unit) {
|
||||
return applyTimezone(DateDiff.diffValueOf(fieldReference, unit).toDate(dateReference()), timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that calculates the difference (in {@literal units) to the date given
|
||||
* {@literal value}. @param value anything the resolves to a valid date. Must not be {@literal null}.
|
||||
*
|
||||
* @param unit the unit of measure. Must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
* @since 3.3
|
||||
*/
|
||||
public DateDiff diff(Object value, String unit) {
|
||||
return applyTimezone(DateDiff.diffValue(value, unit).toDate(dateReference()), timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the year portion of a date.
|
||||
*
|
||||
@@ -2550,6 +2586,114 @@ public class DateOperators {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $dateDiff}.<br />
|
||||
* <strong>NOTE:</strong> Requires MongoDB 5.0 or later.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 3.3
|
||||
*/
|
||||
public static class DateDiff extends TimezonedDateAggregationExpression {
|
||||
|
||||
private DateDiff(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the number of {@literal units} of the result of the given {@link AggregationExpression expression} to a
|
||||
* {@link #toDate(Object) start date}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @param unit must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public static DateDiff diffValueOf(AggregationExpression expression, String unit) {
|
||||
return diffValue(expression, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the number of {@literal units} from a {@literal field} to a {@link #toDate(Object) start date}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @param unit must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public static DateDiff diffValueOf(String fieldReference, String unit) {
|
||||
return diffValue(Fields.field(fieldReference), unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the number of {@literal units} to a {@link #toDate(Object) start date}.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @param unit must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public static DateDiff diffValue(Object value, String unit) {
|
||||
|
||||
Map<String, Object> args = new HashMap<>();
|
||||
args.put("unit", unit);
|
||||
args.put("endDate", value);
|
||||
return new DateDiff(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the start date, in UTC, for the addition operation.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public DateDiff toDateOf(AggregationExpression expression) {
|
||||
return toDate(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the start date, in UTC, for the addition operation.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public DateDiff toDateOf(String fieldReference) {
|
||||
return toDate(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the start date, in UTC, for the addition operation.
|
||||
*
|
||||
* @param dateExpression anything that evaluates to a valid date. Must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public DateDiff toDate(Object dateExpression) {
|
||||
return new DateDiff(append("startDate", dateExpression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally set the {@link Timezone} to use. If not specified {@literal UTC} is used.
|
||||
*
|
||||
* @param timezone must not be {@literal null}. Consider {@link Timezone#none()} instead.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public DateDiff withTimezone(Timezone timezone) {
|
||||
return new DateDiff(appendTimezone(argumentMap(), timezone));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start day of the week if the unit if measure is set to {@literal week}. Uses {@literal Sunday} by
|
||||
* default.
|
||||
*
|
||||
* @param day must not be {@literal null}.
|
||||
* @return new instance of {@link DateDiff}.
|
||||
*/
|
||||
public DateDiff startOfWeek(Object day) {
|
||||
return new DateDiff(append("startOfWeek", day));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$dateDiff";
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends TimezonedDateAggregationExpression> T applyTimezone(T instance, Timezone timezone) {
|
||||
return !ObjectUtils.nullSafeEquals(Timezone.none(), timezone) && !instance.hasTimezone()
|
||||
|
||||
@@ -145,6 +145,7 @@ public class MethodReferenceNode extends ExpressionNode {
|
||||
|
||||
// DATE OPERATORS
|
||||
map.put("dateAdd", mapArgRef().forOperator("$dateAdd").mappingParametersTo("startDate", "unit", "amount", "timezone"));
|
||||
map.put("dateDiff", mapArgRef().forOperator("$dateDiff").mappingParametersTo("startDate", "endDate", "unit","timezone", "startOfWeek"));
|
||||
map.put("dayOfYear", singleArgRef().forOperator("$dayOfYear"));
|
||||
map.put("dayOfMonth", singleArgRef().forOperator("$dayOfMonth"));
|
||||
map.put("dayOfWeek", singleArgRef().forOperator("$dayOfWeek"));
|
||||
|
||||
@@ -40,5 +40,21 @@ class DateOperatorsUnitTests {
|
||||
.toDocument(Aggregation.DEFAULT_CONTEXT)).isEqualTo(Document.parse(
|
||||
"{ $dateAdd: { startDate: \"$purchaseDate\", unit: \"day\", amount: 3, timezone : \"America/Chicago\" } }"));
|
||||
}
|
||||
|
||||
@Test // GH-3713
|
||||
void rendersDateDiff() {
|
||||
|
||||
assertThat(
|
||||
DateOperators.dateOf("purchaseDate").diffValueOf("delivered", "day").toDocument(Aggregation.DEFAULT_CONTEXT))
|
||||
.isEqualTo(Document
|
||||
.parse("{ $dateDiff: { startDate: \"$purchaseDate\", endDate: \"$delivered\", unit: \"day\" } }"));
|
||||
}
|
||||
|
||||
@Test // GH-3713
|
||||
void rendersDateDiffWithTimezone() {
|
||||
|
||||
assertThat(DateOperators.dateOf("purchaseDate").withTimezone(Timezone.valueOf("America/Chicago"))
|
||||
.diffValueOf("delivered", "day").toDocument(Aggregation.DEFAULT_CONTEXT)).isEqualTo(Document.parse(
|
||||
"{ $dateDiff: { startDate: \"$purchaseDate\", endDate: \"$delivered\", unit: \"day\", timezone : \"America/Chicago\" } }"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1044,6 +1044,11 @@ public class SpelExpressionTransformerUnitTests {
|
||||
assertThat(transform("dateAdd(purchaseDate, 'day', 3)")).isEqualTo(Document.parse("{ $dateAdd: { startDate: \"$purchaseDate\", unit: \"day\", amount: 3 } }"));
|
||||
}
|
||||
|
||||
@Test // GH-3713
|
||||
void shouldRenderDateDiff() {
|
||||
assertThat(transform("dateDiff(purchaseDate, delivered, 'day')")).isEqualTo(Document.parse("{ $dateDiff: { startDate: \"$purchaseDate\", endDate: \"$delivered\", unit: \"day\" } }"));
|
||||
}
|
||||
|
||||
private Object transform(String expression, Object... params) {
|
||||
Object result = transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params);
|
||||
return result == null ? null : (!(result instanceof org.bson.Document) ? result.toString() : result);
|
||||
|
||||
Reference in New Issue
Block a user