I have a Postgres table that looks like this:
CREATE TABLE products(
id string,
attributes jsonb,
PRIMARY KEY(id)
);
An example of attributes field could be like:
{
"endDate": [
"2024-02-20T21:00:00.000Z"
],
"countries": [
"US","IT","ES"
],
"type": [
"RETAIL"
],
"startDate": [
"2024-02-13T08:00:00.000Z"
],
"categories": [
"ELECTRONICS"
],
"currency": [
"USD"
],
"status": [
"ACTIVE"
]
}
I need to create filter where as an input I might get a list of countries e.g. ["US","MX"] for which each product having one of these countries would match criteria and/or where startDate might be after certain provided date. I'm also interested in performance of such query, since this table might be really large.
I've tried sto filter products by countries using this query:
SELECT *
FROM products
WHERE
(attributes @> '{ "countries": ["US","MX","JP"] }')
But this query would list only products which have all 3 provided countries. I need to have at least one country match, and in this example, it has "US" so it should be match.
It would be trivial on a normalised structure, but until you find time and budget to change it, you can use
jsonbJSONPath expressions with@@predicate check operator: demoIf you pair it with a GIN index:
You'll see
@@speed up significantly thanks to index scans:That's a test on 40k random sample resembling yours. It's also visible that not the entire JSONPath is supported by the index, hence the re-check:
The part with date comparison using
>doesn’t qualify, which is why a recheck is necessary. Searches where you don’t need the>should be faster.If you're dealing with non-uniform timestamp formats, you might want to add a
.datetime()method in there.