From 620281a452ae8948ca367e4dcb9ec9ec953d59df Mon Sep 17 00:00:00 2001 From: sathish256 <17120479+sathish256@users.noreply.github.com> Date: Thu, 4 Jun 2026 00:56:53 +0530 Subject: [PATCH] Add isNull() to ComparisonOperators. Introduce an additive isNull() builder on ComparisonOperators and its Eq operator that renders to { $eq: [ , null ] }. This lets users compare a field or expression to null without the previous workaround of passing a null-returning expression, while leaving the existing equalToValue(...) null-rejection contract unchanged. Closes #3473 Signed-off-by: sathish256 <17120479+sathish256@users.noreply.github.com> --- .../core/aggregation/ComparisonOperators.java | 28 +++++++++++++++++++ .../ProjectionOperationUnitTests.java | 10 +++++++ 2 files changed, 38 insertions(+) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ComparisonOperators.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ComparisonOperators.java index 16128f522f..a87a363cda 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ComparisonOperators.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ComparisonOperators.java @@ -26,6 +26,7 @@ * Gateway to {@literal comparison expressions}. * * @author Christoph Strobl + * @author sathish256 * @since 1.10 */ public class ComparisonOperators { @@ -147,6 +148,18 @@ public Eq equalToValue(Object value) { return createEq().equalToValue(value); } + /** + * Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first + * value is equal to {@literal null}. + * + * @return new instance of {@link Eq}. + * @since 5.1 + */ + @Contract(" -> new") + public Eq isNull() { + return createEq().isNull(); + } + @SuppressWarnings("NullAway") private Eq createEq() { return usesFieldRef() ? Eq.valueOf(fieldReference) : Eq.valueOf(expression); @@ -505,6 +518,21 @@ public Eq equalToValue(Object value) { Assert.notNull(value, "Value must not be null"); return new Eq(append(value, Expand.KEEP_SOURCE)); } + + /** + * Creates new {@link Eq} with all previously added arguments appending {@literal null}. Renders to + * {@code {$eq: [..., null]}}. + * + * @return new instance of {@link Eq}. + * @since 5.1 + */ + @Contract(" -> new") + public Eq isNull() { + + List args = values(); + args.add(null); + return new Eq(args); + } } /** diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperationUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperationUnitTests.java index b992ec1737..6bbfe1c896 100755 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperationUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperationUnitTests.java @@ -54,6 +54,7 @@ * @author Christoph Strobl * @author Divya Srivastava * @author Mark Paluch + * @author sathish256 */ public class ProjectionOperationUnitTests { @@ -1508,6 +1509,15 @@ void shouldRenderEqAggregationExpressionWithListComparison() { assertThat(agg).isEqualTo(Document.parse("{ $project: { eq250: { $eq: [\"$qty\", [250]]} } }")); } + @Test // GH-3473 + void shouldRenderEqNullAggregationExpression() { + + Document agg = project().and(ComparisonOperators.valueOf("qty").isNull()).as("isNull") + .toDocument(Aggregation.DEFAULT_CONTEXT); + + assertThat(agg).isEqualTo(Document.parse("{ $project: { isNull: { $eq: [\"$qty\", null]} } }")); + } + @Test // DATAMONGO-1536 void shouldRenderGtAggregationExpression() {