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.
2
Answers
It would be trivial on a normalised structure, but until you find time and budget to change it, you can use
jsonb
JSONPath 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:
… which means date comparison with
>
won’t qualify, but your searches limited to specific data points should all fit the criteria.If you’re dealing with non-uniform timestamp formats, you might want to add a
.datetime()
method in there.You can use any of the following solutions:
?|
INTERSECT
against the array.db<>fiddle