avatarChunting Wu

Summary

The article discusses the new JSON_TABLE feature in PostgreSQL 17, comparing it to the previous JSONB functionality and assessing its practical differences and advantages in handling JSON data within SQL queries.

Abstract

The recent release of PostgreSQL 17 introduced the JSON_TABLE feature, which is designed to enhance the database's capabilities for handling JSON data. The article compares JSON_TABLE with the previously available JSONB format, providing examples to illustrate the differences in querying JSON structures. While JSON_TABLE is seen as providing syntactic sugar and not a revolutionary change for simple queries, it demonstrates advantages in more complex scenarios, such as when dealing with nested JSON data or when type casting is required for comparisons. The author appreciates the continued improvement of PostgreSQL's document database features, suggesting that JSON_TABLE is a step forward in structuring unstructured data and may influence other SQL-based databases to follow suit.

Opinions

  • The author considers JSON_TABLE to be a modest improvement, offering syntactic sugar rather than a significant change for simple JSON queries.
  • There is a sense of initial disappointment, as the author was expecting more groundbreaking features from JSON_TABLE.
  • The author acknowledges the advantages of JSON_TABLE in complex queries, particularly its ability to simplify SELECT and WHERE clauses when dealing with nested JSON structures.
  • The author is pleased with PostgreSQL's ongoing enhancement of document database features, viewing JSON_TABLE as a positive development that could drive competition and innovation in SQL-based databases.
  • The article suggests that JSON_TABLE opens up more possibilities for the future of structuring unstructured data within PostgreSQL.

PostgreSQL 17’s JSON_TABLE isn’t Particularly Powerful

Exploring practical differences between JSONB and JSON_TABLE in PostgreSQL 17

My girl

Recently Postgres 17 was released, and one of the features interesting to me was the JSON_TABLE keyword. Postgres has always had an ambition to dominate the database market, and of course that includes document databases.

After the release of JSONB support in previous versions of Postgres, this time JSON structures have been made more descriptive. I was expecting a lot of groundbreaking, but JSON_TABLE looks a bit "ordinary". In my opinion, JSON_TABLE just provides syntactic sugar, not much difference in usage.

Let’s take a quick look at some examples to get a feel for the difference between JSON_TABLE and the JSONB of the past.

Preparation

Let’s start by creating a table. In order to be as close to the document database as possible, we’ll use a single JSONB column to store all the order data, including the order item and the customer.

CREATE TABLE orders (
  id serial PRIMARY KEY,
  order_data JSONB
);

Then we put in two orders, each with two items.

INSERT INTO orders (order_data) VALUES
('{
  "items": [
    { "name": "Laptop", "price": 1200 },
    { "name": "Mouse", "price": 25 }
  ],
  "customer": { "id": 123, "name": "John Doe" }
}'),
('{
  "items": [
    { "name": "Keyboard", "price": 100 },
    { "name": "Monitor", "price": 300 }
  ],
  "customer": { "id": 456, "name": "Jane Smith" }
}');

Okay, let’s experience JSON_TABLE.

JSON_TABLE vs. JSONB

In the past, when we wanted to query for orders with Laptop we would manipulate items through jsonb_array_elements.

SELECT
  item->>'name' AS item_name,
  item->>'price' AS item_price,
  order_data -- whole order including Laptop
FROM
  orders,
  jsonb_array_elements(order_data->'items') AS item
WHERE
  item->>'name' = 'Laptop';

So what would this query look like with JSON_TABLE? Let's see the following example.

SELECT
  jt.item_name,
  jt.item_price,
  order_data
FROM orders o,
  json_table(o.order_data, '$.items[*]'
  COLUMNS (
    item_name TEXT PATH '$.name',
    item_price NUMERIC PATH '$.price'
  )) AS jt
WHERE jt.item_name = 'Laptop';

I have to say the difference is not obvious, but that’s partly because string matching is pretty simple. If we want to look up the price of an item, we’ll start to see the advantages of JSON_TABLE.

Suppose we want to find an order with an item price less than 100, we use the original JSONB as follows.

SELECT
  item->>'name' AS item_name,
  item->>'price' AS item_price,
  order_data
FROM
  orders,
  jsonb_array_elements(order_data->'items') AS item
WHERE
  (item->>'price')::numeric < 100;

We have to add explicit type casts so that we can compare numbers. But in JSON_TABLE query, since there are already defined type casts, we can compare directly.

SELECT
  jt.item_name,
  jt.item_price,
  order_data
FROM orders o,
  json_table(o.order_data, '$.items[*]'
  COLUMNS (
    item_name TEXT PATH '$.name',
    item_price NUMERIC PATH '$.price'
  )) AS jt
WHERE jt.item_price < 100;

Nested JSON

Now we’ve familiarized ourselves with general JSON manipulation, let’s look at the benefits of nested JSON in a JSON_TABLE.

Let’s start by inserting a few test data.

INSERT INTO orders (order_data) VALUES
('{"order": {"items": [{"name": "Laptop", "price": 1200, "details": {"warranty": "2 years", "color": "gray"}}, {"name": "Mouse", "price": 25, "details": {"warranty": "1 year", "color": "black"}}], "customer": {"id": 123, "name": "John Doe"}}}'),
('{"order": {"items": [{"name": "Keyboard", "price": 70, "details": {"warranty": "1 year", "color": "blue"}}, {"name": "Monitor", "price": 300, "details": {"warranty": "3 years", "color": "black"}}], "customer": {"id": 456, "name": "Jane Smith"}}}'),
('{"order": {"items": [{"name": "Tablet", "price": 400, "details": {"warranty": "2 years", "color": "white"}}], "customer": {"id": 789, "name": "Alice Johnson"}}}');

There is now an additional details attribute for each order item, which contains the color and warranty.

I would like to check the items that are blue in color, and I can do this with JSONB.

SELECT
  item->>'name' AS item_name,
  item->>'price' AS item_price,
  item->'details'->>'warranty' AS warranty
FROM
  orders,
  jsonb_array_elements(order_data->'order'->'items') AS item
WHERE
  item->'details'->>'color' = 'blue';

As we can see from the WHERE clause above, our chain is starting to get longer. But in the JSON_TABLE query we can keep the WHERE simple.

SELECT
  jt.item_name,
  jt.item_price,
  jt.warranty
FROM orders o,
  json_table(o.order_data, '$.order.items[*]'
  COLUMNS (
    item_name TEXT PATH '$.name',
    item_price NUMERIC PATH '$.price',
    warranty TEXT PATH '$.details.warranty',
    color TEXT PATH '$.details.color'
  )) AS jt
WHERE jt.color = 'blue';

Conclusion

In a simple JSON query, JSON_TABLE really doesn't have any advantage at all. But when the query gets complex, the fact that SELECT and WHERE can still be kept simple under the JSON_TABLE structure is a big advantage.

Personally, I’m happy to see Postgres continue to improve its document database features, which will probably force other SQL based databases to start following along.

Overall, JSON_TABLE is a step forward, and there are many more possibilities for structuring unstructured data in the future.

Postgresql
Json
Software Development
Document Database
Mongodb
Recommended from ReadMedium