Skip to content

Add ALL and ONE array filter operators for MongoDB and Postgres - #323

Open
lrathod wants to merge 1 commit into
hypertrace:mainfrom
lrathod:ASP-3008/array-match-all-one-operators
Open

Add ALL and ONE array filter operators for MongoDB and Postgres#323
lrathod wants to merge 1 commit into
hypertrace:mainfrom
lrathod:ASP-3008/array-match-all-one-operators

Conversation

@lrathod

@lrathod lrathod commented Aug 27, 2026

Copy link
Copy Markdown

Summary

Adds two new ArrayOperator values for filtering on array-valued attributes:

  • ALL — array attribute must contain every value specified in the filter
  • ONE — array attribute must contain exactly one element, and that element must be one of the specified values

MongoDB

  • ALL{"$expr": {"$setIsSubset": [<values>, {"$ifNull": ["$<arrayPath>", []]}]}} (set containment, null-safe)
  • ONE$and of $size == 1 and $in on $arrayElemAt [path, 0] (cardinality + membership)

Postgres

  • Native array columns (flat collections): ALLCOALESCE(col, ARRAY[]::type[]) @> ?; ONEarray_length(...) = 1 AND col && ?
  • JSONB array paths (nested documents): ALL(CASE WHEN jsonb_typeof(path) = 'array' THEN path ELSE '[]'::jsonb END) @> ?::jsonb; ONEjsonb_array_length(...) = 1 AND (path @> ?::jsonb OR ...) per value
  • SQL array type inferred from the constant values via PostgresDataType.fromJavaValue()

Design note

Both parsers require the inner RelationalExpression to carry a constant value list; a non-constant RHS throws UnsupportedOperationException. This is intentional — ALL/ONE are set-level operators, unlike ANY which supports arbitrary per-element sub-filters.

Test plan

  • 6 new unit tests in MongoArrayFilterParserTest (operator structure, $ifNull guards, single-value, non-constant RHS rejection, no double $expr wrapping)
  • 5 new unit tests in PostgresQueryParserTest (ALL/ONE × JSONB/native array, nested JSONB path)
  • 2 new parameterized integration tests in ArrayFiltersQueryIntegrationTest (Mongo + Postgres) with 3 new JSON fixtures — run in CI
  • :document-store:build (compile + unit tests + spotless) passes locally

Made with Cursor

Add two new ArrayOperator values for filtering on array-valued attributes:
- ALL: array attribute must contain every value specified in the filter
- ONE: array attribute must contain exactly one element, and that element
  must be one of the specified values

MongoDB: ALL uses $setIsSubset with an $ifNull guard; ONE combines
$size == 1 with $in on the first element via $arrayElemAt.

Postgres: native array columns use @> (ALL) and array_length + && (ONE);
JSONB array paths use jsonb_typeof-guarded @> containment and
jsonb_array_length respectively.

Both parsers require the inner filter to carry a constant value list;
non-constant RHS expressions throw UnsupportedOperationException since
these are set-level operators, not per-element predicates like ANY.

Co-authored-by: Cursor <cursoragent@cursor.com>
return value instanceof List ? (List<?>) value : List.of(value);
}

private PostgresDataType resolvePostgresDataType(final List<?> values) {

@suddendust suddendust Aug 31, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid a runtime check? ArrayIdentifierExpression contains DataType that can be extracted statically.

@suddendust

Copy link
Copy Markdown
Contributor

What about operators for nested json arrays?

@suddendust

Copy link
Copy Markdown
Contributor

Lets add some integration tests? You can add in DocStoreQueryV1Test.

*/
@ParameterizedTest
@ArgumentsSource(AllProvider.class)
void getDocumentsContainingAllGivenValues(final String dataStoreName)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see we already have ITs. Can we move them to DocStoreQueryV1Test?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants