Skip to content

feat: add array_contains and array_overlaps operators to pgvector filters#3459

Open
abhay23-AI wants to merge 1 commit into
deepset-ai:mainfrom
abhay23-AI:pgvector-array-ops-clean
Open

feat: add array_contains and array_overlaps operators to pgvector filters#3459
abhay23-AI wants to merge 1 commit into
deepset-ai:mainfrom
abhay23-AI:pgvector-array-ops-clean

Conversation

@abhay23-AI

Copy link
Copy Markdown
Contributor

What

Adds two metadata filter operators to the pgvector document store for querying JSONB array fields, as requested in #1351:

  • array_contains: the meta array must contain all of the given values
  • array_overlaps: the meta array must share at least one element with the given list
# docs whose meta.tags contains both tag1 AND tag2
{"field": "meta.tags", "operator": "array_contains", "value": ["tag1", "tag2"]}

# docs whose meta.tags contains tag1 OR tag3
{"field": "meta.tags", "operator": "array_overlaps", "value": ["tag1", "tag3"]}

How

meta is stored as a JSONB column, so list metadata lands as a native JSON array. The existing scalar operators access meta with the ->> (text) accessor, which can't drive the JSONB array operators, so I added a small _treat_meta_field_as_jsonb helper that uses the -> (jsonb) accessor with no cast:

  • array_contains generates meta->'field' @> %s with the value wrapped as Jsonb(...). jsonb @> jsonb is true when the left array contains every element of the right one.
  • array_overlaps generates meta->'field' ?| %s. jsonb ?| text[] is true when any of the given strings exist as top level array elements.

Field names are still embedded via SQLLiteral, so this stays injection safe. array_overlaps validates that the values are strings (the ?| operator only matches string elements) and both operators raise FilterError on a non list value, matching the style of the existing in / not in operators.

Context

This picks up the work from the earlier #1352, which got closed for inactivity. @julian-risch said back then to feel free to reopen, and since the pgvector integration was refactored in #1547 to build SQL with psycopg Composable objects, I redid it fresh against the current code rather than reviving the stale branch. The old undefined Jsonb import concern from that PR is moot now since Jsonb is already imported in filters.py.

Testing

  • Unit tests for SQL rendering, param wrapping, and the validation error paths (no DB needed).
  • Integration tests covering contains all, contains single, overlaps, no match, and a combined AND filter, run against a real pgvector/pgvector:pg17 container (the same image CI uses).

Full pgvector suite locally: 162 integration passed, all unit passed, fmt-check and mypy clean.

One open question for reviewers: I kept array_overlaps string only with a hard FilterError for non string values, since ?| only matches strings and the issue's use case is tags. If you'd rather support numeric/object arrays too I can switch it to a jsonb_array_elements based approach, just let me know.

Resolves #1351

@abhay23-AI abhay23-AI requested a review from a team as a code owner June 17, 2026 16:10
@abhay23-AI abhay23-AI requested review from julian-risch and removed request for a team June 17, 2026 16:10
@github-actions github-actions Bot added integration:pgvector type:documentation Improvements or additions to documentation labels Jun 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Coverage report (pgvector)

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  integrations/pgvector/src/haystack_integrations/document_stores/pgvector
  filters.py 119, 281
Project Total  

This report was generated by python-coverage-comment-action

@abhay23-AI

Copy link
Copy Markdown
Contributor Author

hi @julian-risch, gentle nudge on this one when you get a chance. it adds the array_contains and array_overlaps pgvector operators you invited me to reopen from the old #1352, rebased and green (the py 3.10 and 3.14 checks pass). fwiw the auto labeler tagged it type:documentation but it's a feature, in case that helps triage. happy to adjust anything.

…ters

Adds two metadata filter operators for querying JSONB array fields in the
pgvector document store:

- array_contains: the meta array must contain ALL of the given values
  (SQL `meta->'field' @> %s`, value wrapped as Jsonb)
- array_overlaps: the meta array must share AT LEAST ONE element with the
  given list of strings (SQL `meta->'field' ?| %s`)

Both access the meta value as JSONB via the `->` accessor (the scalar
operators use `->>` text extraction, which is incompatible with JSONB array
operators) through a new `_treat_meta_field_as_jsonb` helper. array_overlaps
validates that values are strings and both raise FilterError on non-list
values. Field names stay embedded via SQLLiteral so injection is not possible.

Resolves deepset-ai#1351
@abhay23-AI abhay23-AI force-pushed the pgvector-array-ops-clean branch from 54abba0 to 720f070 Compare July 6, 2026 09:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integration:pgvector type:documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support array contains and array overlaps in pgvector metadata filtering

1 participant