How To Query a JSONB Array of Objects as a Recordset in PostgreSQL
By: Gravity Well, Rob Tomlin
Tags: Database, Postgresql, Postgres, NoSQL, Json

Let’s Get Started

Building Our Data

Open pgAdmin and create a database as desired. Right-Click on the database name and choose Query Tool. Run the snippet below to create a simple table that will have an id, purchaser name and a jsonb column that stores an array of json objects, which will store items purchased.

CREATE TABLE public.purchases

(

id serial PRIMARY KEY,

purchaser varchar(50),

items_purchased jsonb

);

4. Run the snippet below to insert four records in to the table.

INSERT INTO purchases (purchaser,items_purchased) VALUES ('Bob','[{

"productid": "1",

"name": "Dell 123 Laptop Computer",

"price": "1300.00" },

{

"productid": "2",

"name": "Mechanical Keyboard",

"price": "120.00" }

]'); INSERT INTO purchases (purchaser,items_purchased) VALUES ('Carol','[{

"productid": "3",

"name": "Virtual Keyboard",

"price": "150.00" }, {

"productid": "1",

"name": "Dell 123 Laptop Computer",

"price": "1300.00" },

{

"productid": "8",

"name": "LG Ultrawide Monitor",

"price": "190.00" }

]'); INSERT INTO purchases (purchaser,items_purchased) VALUES ('Ted','[{

"productid": "6",

"name": "Ergonomic Keyboard",

"price": "90.00" },

{

"productid": "7",

"name": "Dell 789 Desktop Computer",

"price": "120.00" }

]'); INSERT INTO purchases (purchaser,items_purchased) VALUES ('Alice','[{

"productid": "7",

"name": "Dell 789 Desktop Computer",

"price": "120.00" },

{

"productid": "2",

"name": "Mechanical Keyboard",

"price": "120.00" }

]');

5. Run the snippet below to see,

select * from purchases;

purchases with jsonb column of items purchased

Our Function

Understanding jsonb_to_recordset(jsonb data)

Builds an arbitrary set of records from a JSON array of objects (see note below). As with all functions returning record, the caller must explicitly define the structure of the record with an AS clause.

Note:

Extracted key values can then be referenced in other parts of the query, like WHERE clauses.

What does “the caller must explicitly define the structure of the record with an AS clause.” mean?

This means basically that we are defining the structure of our recordset , the columns and their data type. Similar to defining a relational table structure.

Examine the following code.

select * from purchases,jsonb_to_recordset(purchases.items_purchased) as items(name text);

In the FROM clause we reference the table and the jsonb column, purchases.items, which is passed to the jsonb_to_recordset() function. It returns a set of Key/Value pairs that we must define the storage for.

In the AS clause we choose an arbitrary name, items, for our recordset structure, the storage of the Key/Values.

In parentheses would be a comma separated list of the Keys we want (in this case just name) and its data type, text.

For each Key, a new column is created when the query is run .

. Since a new column is created, we can reference it in the Select, Where, Group By and Order by clauses.

Run the code above to get,

Observe the new column, name. The object Key is the column name and the Value the data.

Try this snippet to create two columns.

select * from purchases,jsonb_to_recordset(purchases.items_purchased) as items(name text, price text);

Observe two new columns and data

Using Our New Columns

Now that we have the ability to create columns from our jsonb Keys, we can reference them in Select, Where, Group By and Order By clauses.

Try each of the following

Using the column in Select and Where

select purchaser,items.name from purchases,jsonb_to_recordset(purchases.items_purchased) as items(name text)

where items.name like '%Monitor';

2. Using the column in Select and Where

select purchaser,items.name, items.price from purchases,jsonb_to_recordset(purchases.items_purchased) as items(name text, price text)

where TO_NUMBER(items.price,'9999')>=1000

Note: Because our prices are text, we needed to convert to a number. More on TO_NUMBER() can be found here.

3. Using a column in a Group By

select items.name, count(*) as num from purchases,jsonb_to_recordset(purchases.items_purchased) as items(name text)

group by items.name

order by num Desc

Conclusion

As mentioned before, this is not the only JSON function. There are many functions and operators for JSON data.

I am exploring them everyday as I built a RESTful API for a PERN stack.

If you found this useful, start exploring json, jsonb and the other operators and functions for JSON as well as the regular SQL operations available in PostgreSQL.

Thank you for reading and coding along!

You may also enjoy,