Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Querying data within JSON array data field

Currently playing with JSON fields in postgres 9.3 for the first time and Im running into some difficulty with querying arrays.

The field with the JSON array data type is called 'accounts' and some sample data would be as follows

[{name: "foo", account_id: "123"}, {name: "bar", account_id: "321"}]

I want to be able to find the id of the company that owns account_id 123 for example. The query that I'm having trouble with currently is as follows:

select id from companies where json_array_elements(accounts)->>'account_id' = '123'

This results in an error:

argument of WHERE must not return a set

like image 248
cgallagher Avatar asked Feb 10 '14 10:02

cgallagher


People also ask

How can I access specific data from JSON?

Getting a specific property from a JSON response object Instead, you select the exact property you want and pull that out through dot notation. The dot ( . ) after response (the name of the JSON payload, as defined arbitrarily in the jQuery AJAX function) is how you access the values you want from the JSON object.

Does JSON allow querying?

You can query JSON data using a simple dot notation or, for more functionality, using SQL/JSON functions and conditions. You can create and query a data guide that summarizes the structure and type information of a set of JSON documents.


1 Answers

json_array_elements(...) returns a set, and so does the result of applying ->> and = to the set. Observe:

regress=> select json_array_elements('[{"name": "foo", "account_id": "123"}, {"name": "bar", "account_id": "321"}]') ->> 'account_id' = '123';
 ?column? 
----------
 t
 f
(2 rows)

You'd expect to just be able to write '123' = ANY (...) but that's not supported without an array input, unfortunately. Surprisingly, neither is '123' IN (...), something I think we're going to have to fix.

So, I'd use LATERAL. Here's one way, which will return a company ID multiple times if it has multiple matches:

CREATE TABLE company AS SELECT 1 AS id, '[{"name": "foo", "account_id": "123"}, {"name": "bar", "account_id": "321"}]'::json AS accounts;

SELECT id 
FROM company c,
LATERAL json_array_elements(c.accounts) acc 
WHERE acc ->> 'account_id' = '123';
like image 159
Craig Ringer Avatar answered Sep 28 '22 09:09

Craig Ringer