4

Does PostgreSQL provide any notation/method for putting a constraint on each element of a JSON array?

An example:

create table orders(data json);

insert into orders values ('
{
    "order_id": 45,
    "products": [
        {
            "product_id": 1,
            "name": "Book"
        },
        {
            "product_id": 2,
            "name": "Painting"
        }
    ]
}
');

I can easily add a constraint on the order_id field:

alter table orders add check ((data->>'order_id')::integer >= 1);

Now I need to do the same with product_id. I can put constraint on idividual array items:

alter table orders add check ((data->'products'->0->>'product_id')::integer >= 1);
alter table orders add check ((data->'products'->1->>'product_id')::integer >= 1);
-- etc.

So obviously what I'm looking for is some kind of wildcard operator for matching any JSON array element:

alter table orders add check ((data->'products'->*->>'product_id')::integer >= 1);
--                                               ^ like this

I know that this can be done by extracting products to a separate products table with a foreign key to orders. But I want to know if this is possible within single JSON column, so I can keep that in mind when designing a database schema.

1
  • I think you'd need a subquery to do this at the moment. I'd put my validation in a PL/PgSQL procedure that looped over each array element and use that in my CHECK constraint. Consider raising this use case on the mailing list. Commented Jan 21, 2014 at 1:46

2 Answers 2

3

So I asked this question on PostgreSQL mailing list, as suggested by Craig Ringer, and I've got the answer.

In short the solution is to write a procedure which materializes JSON array to PostgreSQL array:

create function data_product_ids(JSON) returns integer[] immutable  as $$
select array_agg((a->>'product_id')::integer) from
json_array_elements($1->'products') as a $$ language sql ;

and use that procedure in CHECK statment:

alter table orders add check (1 <= ALL(data_product_ids(data)));

For more details on how this works se the answer on PostgreSQL mailing list. Credits to Joel Hoffman.

Sign up to request clarification or add additional context in comments.

Comments

1

From one of the developers of JSON for Postgres

The path stuff does not support wildcards.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.