SlideShare a Scribd company logo
PostgreSQL 9.4
JSON Types and Operators
Pittsburgh PostgreSQL Users Group
2015 December 16
Nicholas Kiraly
github.com/nkiraly
Twitter @NicholasKiraly
kiraly.nicholas@gmail.com
Introductions
github.com/nkiraly Twitter @NicholasKiraly
Systems Integration Engineer
Interface Systems to Produce New Value
Open Source Tools / PostgreSQL / FreeBSD Advocate
To play along with today’s examples, vagrant up with
https://github.com/nkiraly/koadstation/tree/master/dbdevf2
Why should I JSON with PostgreSQL ?
Misconception:
I need one system of record.
But I need to SQL, JSON, and XML so hard!
I have to do transforms, parsing, and derivative storage in my implementation to get
the job done with a single system of record.
Not so!
JSON operators allow for expressions in queries and indexes
Less round-trips for information querying and selection
Streamline and structure your data in one place in your system of record
Base your JSON documents on SQL normalized tables you get best of both worlds!
JSON Types JSON
JSONB
JSON vs JSONB
Stored as Text
Retains Whitespace
Retains Key Order
Retains Duplicate Keys
Index expressions only
Binary
Hierarchy of Key/Value pairs
Whitespace Discarded
Last Duplicate Key Wins
GIN Index support can be leveraged by contains
operators (@> <@ ? ?| ?&)
What about HSTORE?
PostgreSQL extension
For single-depth Key/Value pairs
JSON type objects can be nested to N
HSTORE only stores strings
JSONB uses full range of JSON numbers for
element values
JSON Operators
-> ->>
#> #>>
@> <@
? ?|
?&
->
Get Object Field
'[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::j
son->2
{"c":"baz"}
->>
Get Object Field As Text
'{"a":1,"b":2}'::json->>'b'
2
#>
Get Object At Specified Path
'{"a": {"b":{"c": "foo"}}}'::json#>'{a,b}'
{"c": "foo"}
#>>
Get Object At Specified Path As Text
'{"a":[1,2,3],"b":[4,5,6]}'::json#>>'{
a,2}'
3
JSON / JSONB Operators
@>
Does the left object contain the element on the right?
'{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb
<@
Is the left element and value contained in the right?
'{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb
? Does the field key string exist within the JSON value?
'{"a":1, "b":2}'::jsonb ? 'b'
?| Do any of these key strings exist?
'{"a":1, "b":2, "c":3}'::jsonb ?| array['b', 'c']
JSONB Contains Operators
?& Do all these key strings exist?
'["a", "b"]'::jsonb ?& array['a', 'b']
JSON Queries
SELECT
doc
->’field’
->>’subfield’
FROM sometable
Table JSON Type Usage
suchjson=# CREATE TABLE somejson (
id INTEGER,
doc JSON
);
CREATE TABLE
suchjson=# d+ somejson
Table "public.somejson"
Column | Type | Modifiers | Storage | Stats target | Description
--------+---------+-----------+----------+--------------+-------------
id | integer | | plain | |
doc | json | | extended | |
Insert JSON Data
suchjson=# INSERT INTO somejson VALUES ( 1,
'{
"name": "Nicholas Kiraly",
"address": {
"line1": "5400 City Blvd",
"line2": "Apt B",
"city": "Pittsburgh",
"state": "PA",
"zipcode": "15212"
}
}');
INSERT 0 1
Select JSON Data
suchjson=# SELECT * FROM somejson ;
id | doc
----+--------------------------------
1 | { +
| "name": "Nicholas Kiraly", +
| "address": { +
| "line1": "5400 City Blvd", +
| "line2": "Apt B", +
| "city": "Pittsburgh", +
| "state": "PA", +
| "zipcode": "15212" +
| } +
| }
(1 row)
Extract JSON Data
suchjson=# SELECT doc->>'address' FROM somejson ;
?column?
--------------------------------
{ +
"line1": "5400 City Blvd",+
"line2": "Apt B", +
"city": "Pittsburgh", +
"state": "PA", +
"zipcode": "15212" +
}
(1 row)
Navigate JSON Data
suchjson=# SELECT doc->'address'->>'zipcode' from somejson ;
?column?
----------
15212
(1 row)
suchjson=# SELECT doc->'address'->>'zipcode' = ‘15212’ from somejson ;
?column?
----------
t
(1 row)
JSONB Queries
SELECT
doc
->’field’
->>’subfield’
FROM sometable
Table JSONB Type Usage
suchjson=# CREATE TABLE somejsonb (
id BIGSERIAL,
doc JSONB
);
CREATE TABLE
suchjson=# d+ somejsonb
Table "public.somejsonb"
Column | Type | Modifiers | Storage | Stats target | Description
--------+---------+-----------+----------+--------------+-------------
id | integer | | plain | |
doc | jsonb | | extended | |
Insert JSONB Data
suchjson=# INSERT INTO somejsonb ( doc ) VALUES ( '{
"name": "Nicholas Kiraly",
"address": {
"line1": "5400 City Blvd",
"line2": "Apt B",
"city": "Pittsburgh",
"state": "PA",
"zipcode": "15212"
}
}');
INSERT 0 1
Select JSONB Data
suchjson=# SELECT * FROM somejsonb ;
id | doc
----+-------------------------------------------------------------------------------
-
1 | {"name": "Nicholas Kiraly", "address": {"city": "Pittsburgh", "line1": "5400
City Blvd", "line2": "Apt B", "state": "PA", "zipcode": "15212"}}
(1 row)
Extract JSONB Data
suchjson=# SELECT doc->>'address' FROM somejsonb ;
?column?
------------------------------------------------------------------------------------
-
{"city": "Pittsburgh", "line1": "5400 City Blvd", "line2": "Apt B", "state": "PA",
"zipcode": "15212"}
(1 row)
How many rows have that JSON element?
suchjson=# SELECT COUNT(*) FROM somejsonb ;
count
--------
101104
suchjson=# SELECT COUNT(*) FROM somejsonb WHERE doc->'address'?'line2';
count
-------
56619
JSON Element arrays values
suchjson=# CREATE TABLE shopping_lists (
shopping_list_id BIGSERIAL,
shopping_list_doc JSONB
);
CREATE TABLE
suchjson=# INSERT INTO shopping_lists ( shopping_list_doc ) VALUES (
'{
"listName": "Needed supplies",
"items": [ "diet shasta", "cheese curls", "mousse" ]
}' );
INSERT 0 1
Element arrays as result rows
suchjson=# SELECT * FROM shopping_lists;
shopping_list_id | shopping_list_doc
------------------+-----------------------------------------------------------------
2 | {"items": ["diet shasta", "cheese curls", "mousse"], "listName":
"Needed supplies"}
(1 row)
suchjson=# SELECT jsonb_array_elements_text(shopping_list_doc->'items') AS item FROM
shopping_lists;
item
--------------
diet shasta
cheese curls
mousse
(3 rows)
Multiple rows, Element arrays as result rows
suchjson=# INSERT INTO shopping_lists ( shopping_list_doc ) VALUES (
'{
"listName": "Running low",
"items": [ "grid paper", "cheese curls", "guy fawkes masks" ]
}' );
INSERT 0 1
suchjson=# SELECT jsonb_array_elements_text(shopping_list_doc->'items') AS item FROM
shopping_lists;
item
------------------
diet shasta
cheese curls
mousse
grid paper
cheese curls
guy fawkes masks
(6 rows)
JSON Indexes
SELECT
jsondoc->>’element’
USING INDEX
->> text expression
@> contains
Cost of WHERE JSON ->> Expression
suchjson=# SELECT COUNT(*) FROM somejson;
100101
suchjson=# SELECT COUNT(*) FROM somejson WHERE (doc->'address'->>'zipcode'::text) =
'11100';
1001
suchjson=# EXPLAIN ANALYZE SELECT * FROM somejson WHERE (doc->'address'-
>>'zipcode'::text) = '11100';
QUERY PLAN
------------------------------------------------------------------------------------
Seq Scan on somejson (cost=0.00..4671.77 rows=501 width=36) (actual
time=0.039..316.502 rows=1001 loops=1)
Filter: (((doc -> 'address'::text) ->> 'zipcode'::text) = '11100'::text)
Rows Removed by Filter: 99100
Planning time: 0.093 ms
Execution time: 366.303 ms
Indexing for WHERE JSON ->> Expression
Expressionsuchjson=# CREATE INDEX somejson_zipcode ON somejson
((doc->'address'->>'zipcode'::text));
suchjson=# EXPLAIN ANALYZE SELECT * FROM somejson
WHERE (doc->'address'->>'zipcode'::text) = '11100';
QUERY PLAN
------------------------------------------------------------------------------------
Bitmap Heap Scan on somejson (cost=12.18..1317.64 rows=501 width=36) (actual
time=0.222..3.256 rows=1001 loops=1)
Recheck Cond: (((doc -> 'address'::text) ->> 'zipcode'::text) = '11100'::text)
Heap Blocks: exact=1001
-> Bitmap Index Scan on somejson_zipcode (cost=0.00..12.06 rows=501 width=0)
(actual time=0.210..0.210 rows=1001 loops=1)
Index Cond: (((doc -> 'address'::text) ->> 'zipcode'::text) =
'11100'::text)
Planning time: 0.186 ms
Execution time: 5.214 ms
Cost of WHERE ->Element->> Expression
suchjson=# SELECT COUNT(*) FROM somejsonb;
101104
suchjson=# EXPLAIN ANALYZE SELECT * FROM somejsonb WHERE (doc->'address'-
>>'zipcode'::text) = '11100';
QUERY PLAN
------------------------------------------------------------------------------------
Seq Scan on somejsonb (cost=0.00..4171.32 rows=506 width=159) (actual
time=0.033..58.670 rows=1011 loops=1)
Filter: (((doc -> 'address'::text) ->> 'zipcode'::text) = '11100'::text)
Rows Removed by Filter: 100093
Planning time: 0.134 ms
Execution time: 64.235 ms
Indexing for WHERE ->Element->> Expression
CREATE INDEX somejsonb_zipcode ON somejsonb ((doc->'address'->>'zipcode'::text));
suchjson=# EXPLAIN ANALYZE SELECT * FROM somejsonb WHERE (doc->'address'-
>>'zipcode'::text) = '11100';
QUERY PLAN
-----------------------------------------------------------------------------------
Bitmap Heap Scan on somejsonb (cost=12.22..1253.10 rows=506 width=159) (actual
time=0.440..4.003 rows=1011 loops=1)
Recheck Cond: (((doc -> 'address'::text) ->> 'zipcode'::text) = '11100'::text)
Heap Blocks: exact=1011
-> Bitmap Index Scan on somejsonb_zipcode (cost=0.00..12.09 rows=506 width=0)
(actual time=0.217..0.217 rows=1011 loops=1)
Index Cond: (((doc -> 'address'::text) ->> 'zipcode'::text) =
'11100'::text)
Planning time: 0.113 ms
Execution time: 6.161 ms
Cost of WHERE @> Contains Operator
suchjson=# EXPLAIN ANALYZE SELECT * FROM somejsonb WHERE doc @> '{ "address": {
"zipcode":"11100" } }';
QUERY PLAN
------------------------------------------------------------------------------------
-
Seq Scan on somejsonb (cost=0.00..3665.80 rows=101 width=159) (actual
time=0.019..59.580 rows=1011 loops=1)
Filter: (doc @> '{"address": {"zipcode": "11100"}}'::jsonb)
Rows Removed by Filter: 100093
Planning time: 0.094 ms
Execution time: 64.843 ms
Indexing for WHERE @> Contains Operator
suchjson=# CREATE INDEX somejsonb_gin ON somejsonb USING gin ( doc jsonb_path_ops);
CREATE INDEX
suchjson=# EXPLAIN ANALYZE SELECT * FROM somejsonb WHERE doc @> '{ "address": {
"zipcode":"11100" } }';
QUERY PLAN
------------------------------------------------------------------------------------
-
Bitmap Heap Scan on somejsonb (cost=12.78..349.75 rows=101 width=159) (actual
time=0.376..4.644 rows=1011 loops=1)
Recheck Cond: (doc @> '{"address": {"zipcode": "11100"}}'::jsonb)
Heap Blocks: exact=1011
-> Bitmap Index Scan on somejsonb_gin (cost=0.00..12.76 rows=101 width=0)
(actual time=0.271..0.271 rows=1011 loops=1)
Index Cond: (doc @> '{"address": {"zipcode": "11100"}}'::jsonb)
Planning time: 0.136 ms
Execution time: 6.800 ms
Index Size Cost Considerations
suchjson=# SELECT nspname AS "namespace", relname AS "relation",
pg_size_pretty(pg_relation_size(C.oid)) AS "size"
FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
ORDER BY pg_relation_size(C.oid) DESC;
namespace | relation | size
-----------+-------------------+------------
public | somejsonb | 19 MB
public | somejsonb_zipcode | 2232 kB
public | somejsonb_gin | 1680 kB
public | somejson | 8192 bytes
public | somejsonb_id_seq | 8192 bytes
public | posts | 8192 bytes
(6 rows)
JSON Views
SELECT doc
FROM jsonview
WHERE things
-----------------------------
{ “formatted”: “data” }
Blog Site User Data Model
CREATE TABLE users (
user_id varchar(100) PRIMARY KEY,
user_name varchar(100) NOT NULL,
user_rank integer NOT NULL DEFAULT 10,
user_display_name varchar(200) NOT NULL
user_profile text
);
Blog Site Post Data Model
CREATE TABLE posts (
post_id varchar(100) PRIMARY KEY,
post_date timestamp with time zone,
post_summary varchar(200) NOT NULL,
post_content text NOT NULL,
post_tags varchar(100)[]
);
CREATE TABLE posts_read (
post_id varchar(100) REFERENCES posts(post_id),
user_id varchar(100) REFERENCES users(user_id),
read_date timestamp with time zone NOT NULL,
PRIMARY KEY (post_id, user_id)
);
User Detail JSON View
CREATE VIEW users_json AS
SELECT users.*, row_to_json(users, TRUE)
FROM users ;
SELECT * FROM users_json WHERE user_name = 'rsanchez';
-[ RECORD 1 ]-----+---------------------------------------------------
user_id | rick.sanchez@potp.com
user_name | rsanchez
user_rank | 10
user_display_name | Richard Sanchez
user_profile | Wubba lubba dub-dub!
row_to_json | {"user_id":"rick.sanchez@potp.com",
| "user_name":"rsanchez",
| "user_rank":10,
| "user_display_name":"Richard Sanchez",
| "user_profile":"Wubba lubba dub-dub!"}
Post JSON View
blogsite=#
CREATE VIEW posts_json AS
SELECT posts.*, row_to_json(posts, TRUE)
FROM posts ;
SELECT FROM Post JSON View
blogsite=# SELECT * FROM posts_json WHERE post_id = 'beths-new-bike';
-[ RECORD 1 ]+--------------------------------------------------------------------
post_id | beths-new-bike
post_date | 2015-12-15 04:04:37.985041+00
user_id | beth.smith@rr.com
post_summary | My New Bike
post_content | I got a new bike last night and it's better than a horse
post_tags | {bike,new,suchpedal}
row_to_json | {"post_id":"beths-new-bike",
| "post_date":"2015-12-15T04:04:37.985041+00:00",
| "user_id":"beth.smith@rr.com",
| "post_summary":"My New Bike",
| "post_content":"I got a new bike last night and it's better than a
horse",
| "post_tags":["bike","new","suchpedal"]}
Unread Posts JSON View
CREATE VIEW unread_posts_json AS
-- users that have not read posts
SELECT ur.*, row_to_json(ur, TRUE) AS json
FROM (
-- select u.user_id so view queries can limit to a specific user's unread
posts
SELECT u.user_id, p.post_id, p.post_summary, p.post_date
FROM users AS u CROSS JOIN posts AS p
WHERE NOT EXISTS (
SELECT 1 FROM posts_read
WHERE post_id = p.post_id AND user_id = u.user_id
)
) AS ur;
Posts Data
blogsite=# SELECT * FROM posts;
-[ RECORD 1 ]+---------------------------------------------------------
post_id | beths-new-bike
post_date | 2015-12-15 05:59:26.634021+00
user_id | beth.smith@rr.com
post_summary | My New Bike
post_content | I got a new bike last night and it's better than a horse
post_tags | {bike,new,suchpedal}
-[ RECORD 2 ]+---------------------------------------------------------
post_id | ricks-new-space-van
post_date | 2015-12-15 05:59:26.634021+00
user_id | rick.sanchez@potp.com
post_summary | New Spaceship
post_content | I got a new spaceship last night and -burp- its awesome
post_tags | {spaceship,new,interdimensional}
Select Morty Unread Posts JSON View
blogsite=# -- what posts hasn't Morty read yet?
blogsite=# SELECT json FROM unread_posts_json
WHERE user_id = 'morty.smith@gmail.com';
json
---------------------------------------------------------
{"user_id":"morty.smith@gmail.com", +
"post_id":"beths-new-bike", +
"post_user_id":"beth.smith@rr.com",+
"post_summary":"My New Bike", +
"post_date":"2015-12-15T02:55:59.461635+00:00"}
{"user_id":"morty.smith@gmail.com", +
"post_id":"ricks-new-space-van", +
"post_user_id":"rick.sanchez@potp.com",+
"post_summary":"I Got A New Space Van", +
"post_date":"2015-12-15T02:55:59.461635+00:00"}
(2 rows)
Select Rick Unread Posts JSON View
blogsite=# -- what posts hasn't Rick read yet?
blogsite=# SELECT json FROM unread_posts_json
WHERE user_id = 'rick.sanchez@potp.com';
json
------
(0 rows)
Select Beth Unread Posts JSON View
blogsite=# -- what posts hasn't Beth read yet?
blogsite=# SELECT json FROM unread_posts_json WHERE user_id = 'beth.smith@rr.com';
json
---------------------------------------------------------
{"user_id":"beth.smith@rr.com", +
"post_id":"ricks-new-space-van", +
"post_user_id":"rick.sanchez@potp.com",+
"post_summary":"I Got A New Space Van", +
"post_date":"2015-12-15T02:55:59.461635+00:00"}
(1 row)
Alternate Unread Posts View
CREATE VIEW unread_posts_v2_json AS
-- users that have not read posts
-- alternate version
SELECT ur.*, row_to_json(ur, TRUE) AS json
FROM (
SELECT posts.post_id, posts.post_date, posts.post_summary, users.user_id
-- take the cross product of users and posts
FROM users
INNER JOIN posts ON (
-- filter out the ones that exist in posts_read
(users.user_id, posts.post_id) NOT IN (SELECT user_id, post_id FROM
posts_read)
)
) AS ur;
Common Q&A Topic for PostgreSQL 9.4
No in-place element editing in 9.4
JSON structures must be rebuilt to update element values
jsonb_set() in 9.5 to replace entire sections
Append children elements by the same name to overwrite existing values in 9.4
Regenerate / reselect entire JSON structure
Questions?
Answers!
Feedbacks $#!7$%
SELECT
doc->knowledge
FROM jsonb
WHERE
applied_knowledge
IS NOT NULL
Questions ? Answers ! Feedbacks
PostgreSQL 9.4 JSON Types and Operators
http://www.meetup.com/Pittsburgh-PostgreSQL-Users-Group
Check Out @lfgpgh http://lfgpgh.com
Nicholas Kiraly
github.com/nkiraly
Twitter @NicholasKiraly
kiraly.nicholas@gmail.com
Ad

More Related Content

What's hot (20)

MongoDB - Aggregation Pipeline
MongoDB - Aggregation PipelineMongoDB - Aggregation Pipeline
MongoDB - Aggregation Pipeline
Jason Terpko
 
Full Text Search In PostgreSQL
Full Text Search In PostgreSQLFull Text Search In PostgreSQL
Full Text Search In PostgreSQL
Karwin Software Solutions LLC
 
Back to Basics, webinar 2: La tua prima applicazione MongoDB
Back to Basics, webinar 2: La tua prima applicazione MongoDBBack to Basics, webinar 2: La tua prima applicazione MongoDB
Back to Basics, webinar 2: La tua prima applicazione MongoDB
MongoDB
 
Latinoware
LatinowareLatinoware
Latinoware
kchodorow
 
Back to Basics Webinar 4: Advanced Indexing, Text and Geospatial Indexes
Back to Basics Webinar 4: Advanced Indexing, Text and Geospatial IndexesBack to Basics Webinar 4: Advanced Indexing, Text and Geospatial Indexes
Back to Basics Webinar 4: Advanced Indexing, Text and Geospatial Indexes
MongoDB
 
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
Ontico
 
Webinar: Index Tuning and Evaluation
Webinar: Index Tuning and EvaluationWebinar: Index Tuning and Evaluation
Webinar: Index Tuning and Evaluation
MongoDB
 
Indexing and Query Optimizer (Mongo Austin)
Indexing and Query Optimizer (Mongo Austin)Indexing and Query Optimizer (Mongo Austin)
Indexing and Query Optimizer (Mongo Austin)
MongoDB
 
The Aggregation Framework
The Aggregation FrameworkThe Aggregation Framework
The Aggregation Framework
MongoDB
 
Fast querying indexing for performance (4)
Fast querying   indexing for performance (4)Fast querying   indexing for performance (4)
Fast querying indexing for performance (4)
MongoDB
 
Webinar: Exploring the Aggregation Framework
Webinar: Exploring the Aggregation FrameworkWebinar: Exploring the Aggregation Framework
Webinar: Exploring the Aggregation Framework
MongoDB
 
Indexing with MongoDB
Indexing with MongoDBIndexing with MongoDB
Indexing with MongoDB
MongoDB
 
MongoDB and Indexes - MUG Denver - 20160329
MongoDB and Indexes - MUG Denver - 20160329MongoDB and Indexes - MUG Denver - 20160329
MongoDB and Indexes - MUG Denver - 20160329
Douglas Duncan
 
Webinaire 2 de la série « Retour aux fondamentaux » : Votre première applicat...
Webinaire 2 de la série « Retour aux fondamentaux » : Votre première applicat...Webinaire 2 de la série « Retour aux fondamentaux » : Votre première applicat...
Webinaire 2 de la série « Retour aux fondamentaux » : Votre première applicat...
MongoDB
 
Database Wizardry for Legacy Applications
Database Wizardry for Legacy ApplicationsDatabase Wizardry for Legacy Applications
Database Wizardry for Legacy Applications
Gabriela Ferrara
 
Working with JSON Data in PostgreSQL vs. MongoDB
Working with JSON Data in PostgreSQL vs. MongoDBWorking with JSON Data in PostgreSQL vs. MongoDB
Working with JSON Data in PostgreSQL vs. MongoDB
ScaleGrid.io
 
Indexing and Performance Tuning
Indexing and Performance TuningIndexing and Performance Tuning
Indexing and Performance Tuning
MongoDB
 
MongoDB Aggregation
MongoDB Aggregation MongoDB Aggregation
MongoDB Aggregation
Amit Ghosh
 
PostgreSQL Moscow Meetup - September 2014 - Oleg Bartunov and Alexander Korotkov
PostgreSQL Moscow Meetup - September 2014 - Oleg Bartunov and Alexander KorotkovPostgreSQL Moscow Meetup - September 2014 - Oleg Bartunov and Alexander Korotkov
PostgreSQL Moscow Meetup - September 2014 - Oleg Bartunov and Alexander Korotkov
Nikolay Samokhvalov
 
The Aggregation Framework
The Aggregation FrameworkThe Aggregation Framework
The Aggregation Framework
MongoDB
 
MongoDB - Aggregation Pipeline
MongoDB - Aggregation PipelineMongoDB - Aggregation Pipeline
MongoDB - Aggregation Pipeline
Jason Terpko
 
Back to Basics, webinar 2: La tua prima applicazione MongoDB
Back to Basics, webinar 2: La tua prima applicazione MongoDBBack to Basics, webinar 2: La tua prima applicazione MongoDB
Back to Basics, webinar 2: La tua prima applicazione MongoDB
MongoDB
 
Back to Basics Webinar 4: Advanced Indexing, Text and Geospatial Indexes
Back to Basics Webinar 4: Advanced Indexing, Text and Geospatial IndexesBack to Basics Webinar 4: Advanced Indexing, Text and Geospatial Indexes
Back to Basics Webinar 4: Advanced Indexing, Text and Geospatial Indexes
MongoDB
 
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
Ontico
 
Webinar: Index Tuning and Evaluation
Webinar: Index Tuning and EvaluationWebinar: Index Tuning and Evaluation
Webinar: Index Tuning and Evaluation
MongoDB
 
Indexing and Query Optimizer (Mongo Austin)
Indexing and Query Optimizer (Mongo Austin)Indexing and Query Optimizer (Mongo Austin)
Indexing and Query Optimizer (Mongo Austin)
MongoDB
 
The Aggregation Framework
The Aggregation FrameworkThe Aggregation Framework
The Aggregation Framework
MongoDB
 
Fast querying indexing for performance (4)
Fast querying   indexing for performance (4)Fast querying   indexing for performance (4)
Fast querying indexing for performance (4)
MongoDB
 
Webinar: Exploring the Aggregation Framework
Webinar: Exploring the Aggregation FrameworkWebinar: Exploring the Aggregation Framework
Webinar: Exploring the Aggregation Framework
MongoDB
 
Indexing with MongoDB
Indexing with MongoDBIndexing with MongoDB
Indexing with MongoDB
MongoDB
 
MongoDB and Indexes - MUG Denver - 20160329
MongoDB and Indexes - MUG Denver - 20160329MongoDB and Indexes - MUG Denver - 20160329
MongoDB and Indexes - MUG Denver - 20160329
Douglas Duncan
 
Webinaire 2 de la série « Retour aux fondamentaux » : Votre première applicat...
Webinaire 2 de la série « Retour aux fondamentaux » : Votre première applicat...Webinaire 2 de la série « Retour aux fondamentaux » : Votre première applicat...
Webinaire 2 de la série « Retour aux fondamentaux » : Votre première applicat...
MongoDB
 
Database Wizardry for Legacy Applications
Database Wizardry for Legacy ApplicationsDatabase Wizardry for Legacy Applications
Database Wizardry for Legacy Applications
Gabriela Ferrara
 
Working with JSON Data in PostgreSQL vs. MongoDB
Working with JSON Data in PostgreSQL vs. MongoDBWorking with JSON Data in PostgreSQL vs. MongoDB
Working with JSON Data in PostgreSQL vs. MongoDB
ScaleGrid.io
 
Indexing and Performance Tuning
Indexing and Performance TuningIndexing and Performance Tuning
Indexing and Performance Tuning
MongoDB
 
MongoDB Aggregation
MongoDB Aggregation MongoDB Aggregation
MongoDB Aggregation
Amit Ghosh
 
PostgreSQL Moscow Meetup - September 2014 - Oleg Bartunov and Alexander Korotkov
PostgreSQL Moscow Meetup - September 2014 - Oleg Bartunov and Alexander KorotkovPostgreSQL Moscow Meetup - September 2014 - Oleg Bartunov and Alexander Korotkov
PostgreSQL Moscow Meetup - September 2014 - Oleg Bartunov and Alexander Korotkov
Nikolay Samokhvalov
 
The Aggregation Framework
The Aggregation FrameworkThe Aggregation Framework
The Aggregation Framework
MongoDB
 

Viewers also liked (8)

Matt Misiak 2016
Matt Misiak 2016Matt Misiak 2016
Matt Misiak 2016
Matt Misiak
 
Hirschsprungs disease
Hirschsprungs disease Hirschsprungs disease
Hirschsprungs disease
Arylic Singh
 
Aula virtual
Aula virtualAula virtual
Aula virtual
will19931994
 
Reserva ecológica el ángel
Reserva ecológica el ángelReserva ecológica el ángel
Reserva ecológica el ángel
will19931994
 
PostgreSQL 9.5 Foreign Data Wrappers
PostgreSQL 9.5 Foreign Data WrappersPostgreSQL 9.5 Foreign Data Wrappers
PostgreSQL 9.5 Foreign Data Wrappers
Nicholas Kiraly
 
Banco de preguntas
Banco de preguntasBanco de preguntas
Banco de preguntas
will19931994
 
Presentación victoria_yovicha
Presentación victoria_yovichaPresentación victoria_yovicha
Presentación victoria_yovicha
Alma Monreal
 
seminar report on 3d printing Shubham srivastava
seminar report on 3d printing Shubham srivastavaseminar report on 3d printing Shubham srivastava
seminar report on 3d printing Shubham srivastava
officiallyshubh
 
Matt Misiak 2016
Matt Misiak 2016Matt Misiak 2016
Matt Misiak 2016
Matt Misiak
 
Hirschsprungs disease
Hirschsprungs disease Hirschsprungs disease
Hirschsprungs disease
Arylic Singh
 
Reserva ecológica el ángel
Reserva ecológica el ángelReserva ecológica el ángel
Reserva ecológica el ángel
will19931994
 
PostgreSQL 9.5 Foreign Data Wrappers
PostgreSQL 9.5 Foreign Data WrappersPostgreSQL 9.5 Foreign Data Wrappers
PostgreSQL 9.5 Foreign Data Wrappers
Nicholas Kiraly
 
Banco de preguntas
Banco de preguntasBanco de preguntas
Banco de preguntas
will19931994
 
Presentación victoria_yovicha
Presentación victoria_yovichaPresentación victoria_yovicha
Presentación victoria_yovicha
Alma Monreal
 
seminar report on 3d printing Shubham srivastava
seminar report on 3d printing Shubham srivastavaseminar report on 3d printing Shubham srivastava
seminar report on 3d printing Shubham srivastava
officiallyshubh
 
Ad

Similar to PostgreSQL 9.4 JSON Types and Operators (20)

CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...
CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...
CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...
Ontico
 
Json in Postgres - the Roadmap
 Json in Postgres - the Roadmap Json in Postgres - the Roadmap
Json in Postgres - the Roadmap
EDB
 
Postgres vs Mongo / Олег Бартунов (Postgres Professional)
Postgres vs Mongo / Олег Бартунов (Postgres Professional)Postgres vs Mongo / Олег Бартунов (Postgres Professional)
Postgres vs Mongo / Олег Бартунов (Postgres Professional)
Ontico
 
JSON and the Oracle Database
JSON and the Oracle DatabaseJSON and the Oracle Database
JSON and the Oracle Database
Maria Colgan
 
Postgres Performance for Humans
Postgres Performance for HumansPostgres Performance for Humans
Postgres Performance for Humans
Citus Data
 
Power JSON with PostgreSQL
Power JSON with PostgreSQLPower JSON with PostgreSQL
Power JSON with PostgreSQL
EDB
 
Going Native: Leveraging the New JSON Native Datatype in Oracle 21c
Going Native: Leveraging the New JSON Native Datatype in Oracle 21cGoing Native: Leveraging the New JSON Native Datatype in Oracle 21c
Going Native: Leveraging the New JSON Native Datatype in Oracle 21c
Jim Czuprynski
 
N1QL: What's new in Couchbase 5.0
N1QL: What's new in Couchbase 5.0N1QL: What's new in Couchbase 5.0
N1QL: What's new in Couchbase 5.0
Keshav Murthy
 
Oracle Database - JSON and the In-Memory Database
Oracle Database - JSON and the In-Memory DatabaseOracle Database - JSON and the In-Memory Database
Oracle Database - JSON and the In-Memory Database
Marco Gralike
 
PG Day'14 Russia, Работа со слабо-структурированными данными в PostgreSQL, Ол...
PG Day'14 Russia, Работа со слабо-структурированными данными в PostgreSQL, Ол...PG Day'14 Russia, Работа со слабо-структурированными данными в PostgreSQL, Ол...
PG Day'14 Russia, Работа со слабо-структурированными данными в PostgreSQL, Ол...
pgdayrussia
 
JSON Processing in the Database using PostgreSQL 9.4 :: Data Wranglers DC :: ...
JSON Processing in the Database using PostgreSQL 9.4 :: Data Wranglers DC :: ...JSON Processing in the Database using PostgreSQL 9.4 :: Data Wranglers DC :: ...
JSON Processing in the Database using PostgreSQL 9.4 :: Data Wranglers DC :: ...
Ryan B Harvey, CSDP, CSM
 
The rise of json in rdbms land jab17
The rise of json in rdbms land jab17The rise of json in rdbms land jab17
The rise of json in rdbms land jab17
alikonweb
 
NoSQL Best Practices for PostgreSQL / Дмитрий Долгов (Mindojo)
NoSQL Best Practices for PostgreSQL / Дмитрий Долгов (Mindojo)NoSQL Best Practices for PostgreSQL / Дмитрий Долгов (Mindojo)
NoSQL Best Practices for PostgreSQL / Дмитрий Долгов (Mindojo)
Ontico
 
BGOUG15: JSON support in MySQL 5.7
BGOUG15: JSON support in MySQL 5.7BGOUG15: JSON support in MySQL 5.7
BGOUG15: JSON support in MySQL 5.7
Georgi Kodinov
 
10 Reasons to Start Your Analytics Project with PostgreSQL
10 Reasons to Start Your Analytics Project with PostgreSQL10 Reasons to Start Your Analytics Project with PostgreSQL
10 Reasons to Start Your Analytics Project with PostgreSQL
Satoshi Nagayasu
 
Deep dive to PostgreSQL Indexes
Deep dive to PostgreSQL IndexesDeep dive to PostgreSQL Indexes
Deep dive to PostgreSQL Indexes
Ibrar Ahmed
 
lecture_40_1.pptx
lecture_40_1.pptxlecture_40_1.pptx
lecture_40_1.pptx
RAGULNS1
 
lecture_40_1.ppt
lecture_40_1.pptlecture_40_1.ppt
lecture_40_1.ppt
BalramParmar5
 
MongoDB Basics Introduction along with MapReduce
MongoDB Basics Introduction along with MapReduceMongoDB Basics Introduction along with MapReduce
MongoDB Basics Introduction along with MapReduce
anishachandaran1994
 
MongoDB a été développé par la société basée à New York 10gen en 2007, dans l...
MongoDB a été développé par la société basée à New York 10gen en 2007, dans l...MongoDB a été développé par la société basée à New York 10gen en 2007, dans l...
MongoDB a été développé par la société basée à New York 10gen en 2007, dans l...
marylinlamour
 
CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...
CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...
CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...
Ontico
 
Json in Postgres - the Roadmap
 Json in Postgres - the Roadmap Json in Postgres - the Roadmap
Json in Postgres - the Roadmap
EDB
 
Postgres vs Mongo / Олег Бартунов (Postgres Professional)
Postgres vs Mongo / Олег Бартунов (Postgres Professional)Postgres vs Mongo / Олег Бартунов (Postgres Professional)
Postgres vs Mongo / Олег Бартунов (Postgres Professional)
Ontico
 
JSON and the Oracle Database
JSON and the Oracle DatabaseJSON and the Oracle Database
JSON and the Oracle Database
Maria Colgan
 
Postgres Performance for Humans
Postgres Performance for HumansPostgres Performance for Humans
Postgres Performance for Humans
Citus Data
 
Power JSON with PostgreSQL
Power JSON with PostgreSQLPower JSON with PostgreSQL
Power JSON with PostgreSQL
EDB
 
Going Native: Leveraging the New JSON Native Datatype in Oracle 21c
Going Native: Leveraging the New JSON Native Datatype in Oracle 21cGoing Native: Leveraging the New JSON Native Datatype in Oracle 21c
Going Native: Leveraging the New JSON Native Datatype in Oracle 21c
Jim Czuprynski
 
N1QL: What's new in Couchbase 5.0
N1QL: What's new in Couchbase 5.0N1QL: What's new in Couchbase 5.0
N1QL: What's new in Couchbase 5.0
Keshav Murthy
 
Oracle Database - JSON and the In-Memory Database
Oracle Database - JSON and the In-Memory DatabaseOracle Database - JSON and the In-Memory Database
Oracle Database - JSON and the In-Memory Database
Marco Gralike
 
PG Day'14 Russia, Работа со слабо-структурированными данными в PostgreSQL, Ол...
PG Day'14 Russia, Работа со слабо-структурированными данными в PostgreSQL, Ол...PG Day'14 Russia, Работа со слабо-структурированными данными в PostgreSQL, Ол...
PG Day'14 Russia, Работа со слабо-структурированными данными в PostgreSQL, Ол...
pgdayrussia
 
JSON Processing in the Database using PostgreSQL 9.4 :: Data Wranglers DC :: ...
JSON Processing in the Database using PostgreSQL 9.4 :: Data Wranglers DC :: ...JSON Processing in the Database using PostgreSQL 9.4 :: Data Wranglers DC :: ...
JSON Processing in the Database using PostgreSQL 9.4 :: Data Wranglers DC :: ...
Ryan B Harvey, CSDP, CSM
 
The rise of json in rdbms land jab17
The rise of json in rdbms land jab17The rise of json in rdbms land jab17
The rise of json in rdbms land jab17
alikonweb
 
NoSQL Best Practices for PostgreSQL / Дмитрий Долгов (Mindojo)
NoSQL Best Practices for PostgreSQL / Дмитрий Долгов (Mindojo)NoSQL Best Practices for PostgreSQL / Дмитрий Долгов (Mindojo)
NoSQL Best Practices for PostgreSQL / Дмитрий Долгов (Mindojo)
Ontico
 
BGOUG15: JSON support in MySQL 5.7
BGOUG15: JSON support in MySQL 5.7BGOUG15: JSON support in MySQL 5.7
BGOUG15: JSON support in MySQL 5.7
Georgi Kodinov
 
10 Reasons to Start Your Analytics Project with PostgreSQL
10 Reasons to Start Your Analytics Project with PostgreSQL10 Reasons to Start Your Analytics Project with PostgreSQL
10 Reasons to Start Your Analytics Project with PostgreSQL
Satoshi Nagayasu
 
Deep dive to PostgreSQL Indexes
Deep dive to PostgreSQL IndexesDeep dive to PostgreSQL Indexes
Deep dive to PostgreSQL Indexes
Ibrar Ahmed
 
lecture_40_1.pptx
lecture_40_1.pptxlecture_40_1.pptx
lecture_40_1.pptx
RAGULNS1
 
MongoDB Basics Introduction along with MapReduce
MongoDB Basics Introduction along with MapReduceMongoDB Basics Introduction along with MapReduce
MongoDB Basics Introduction along with MapReduce
anishachandaran1994
 
MongoDB a été développé par la société basée à New York 10gen en 2007, dans l...
MongoDB a été développé par la société basée à New York 10gen en 2007, dans l...MongoDB a été développé par la société basée à New York 10gen en 2007, dans l...
MongoDB a été développé par la société basée à New York 10gen en 2007, dans l...
marylinlamour
 
Ad

Recently uploaded (20)

Best Practices for Collaborating with 3D Artists in Mobile Game Development
Best Practices for Collaborating with 3D Artists in Mobile Game DevelopmentBest Practices for Collaborating with 3D Artists in Mobile Game Development
Best Practices for Collaborating with 3D Artists in Mobile Game Development
Juego Studios
 
Get & Download Wondershare Filmora Crack Latest [2025]
Get & Download Wondershare Filmora Crack Latest [2025]Get & Download Wondershare Filmora Crack Latest [2025]
Get & Download Wondershare Filmora Crack Latest [2025]
saniaaftab72555
 
Microsoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdf
Microsoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdfMicrosoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdf
Microsoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdf
TechSoup
 
Exploring Wayland: A Modern Display Server for the Future
Exploring Wayland: A Modern Display Server for the FutureExploring Wayland: A Modern Display Server for the Future
Exploring Wayland: A Modern Display Server for the Future
ICS
 
Apple Logic Pro X Crack FRESH Version 2025
Apple Logic Pro X Crack FRESH Version 2025Apple Logic Pro X Crack FRESH Version 2025
Apple Logic Pro X Crack FRESH Version 2025
fs4635986
 
The Significance of Hardware in Information Systems.pdf
The Significance of Hardware in Information Systems.pdfThe Significance of Hardware in Information Systems.pdf
The Significance of Hardware in Information Systems.pdf
drewplanas10
 
Top 10 Data Cleansing Tools for 2025.pdf
Top 10 Data Cleansing Tools for 2025.pdfTop 10 Data Cleansing Tools for 2025.pdf
Top 10 Data Cleansing Tools for 2025.pdf
AffinityCore
 
Avast Premium Security Crack FREE Latest Version 2025
Avast Premium Security Crack FREE Latest Version 2025Avast Premium Security Crack FREE Latest Version 2025
Avast Premium Security Crack FREE Latest Version 2025
mu394968
 
🌱 Green Grafana 🌱 Essentials_ Data, Visualizations and Plugins.pdf
🌱 Green Grafana 🌱 Essentials_ Data, Visualizations and Plugins.pdf🌱 Green Grafana 🌱 Essentials_ Data, Visualizations and Plugins.pdf
🌱 Green Grafana 🌱 Essentials_ Data, Visualizations and Plugins.pdf
Imma Valls Bernaus
 
FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...
FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...
FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...
Lionel Briand
 
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
Andre Hora
 
Proactive Vulnerability Detection in Source Code Using Graph Neural Networks:...
Proactive Vulnerability Detection in Source Code Using Graph Neural Networks:...Proactive Vulnerability Detection in Source Code Using Graph Neural Networks:...
Proactive Vulnerability Detection in Source Code Using Graph Neural Networks:...
Ranjan Baisak
 
Top 10 Client Portal Software Solutions for 2025.docx
Top 10 Client Portal Software Solutions for 2025.docxTop 10 Client Portal Software Solutions for 2025.docx
Top 10 Client Portal Software Solutions for 2025.docx
Portli
 
Implementing promises with typescripts, step by step
Implementing promises with typescripts, step by stepImplementing promises with typescripts, step by step
Implementing promises with typescripts, step by step
Ran Wahle
 
Exceptional Behaviors: How Frequently Are They Tested? (AST 2025)
Exceptional Behaviors: How Frequently Are They Tested? (AST 2025)Exceptional Behaviors: How Frequently Are They Tested? (AST 2025)
Exceptional Behaviors: How Frequently Are They Tested? (AST 2025)
Andre Hora
 
Kubernetes_101_Zero_to_Platform_Engineer.pptx
Kubernetes_101_Zero_to_Platform_Engineer.pptxKubernetes_101_Zero_to_Platform_Engineer.pptx
Kubernetes_101_Zero_to_Platform_Engineer.pptx
CloudScouts
 
Odoo ERP for Education Management to Streamline Your Education Process
Odoo ERP for Education Management to Streamline Your Education ProcessOdoo ERP for Education Management to Streamline Your Education Process
Odoo ERP for Education Management to Streamline Your Education Process
iVenture Team LLP
 
Cryptocurrency Exchange Script like Binance.pptx
Cryptocurrency Exchange Script like Binance.pptxCryptocurrency Exchange Script like Binance.pptx
Cryptocurrency Exchange Script like Binance.pptx
riyageorge2024
 
Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...
Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...
Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...
Eric D. Schabell
 
PRTG Network Monitor Crack Latest Version & Serial Key 2025 [100% Working]
PRTG Network Monitor Crack Latest Version & Serial Key 2025 [100% Working]PRTG Network Monitor Crack Latest Version & Serial Key 2025 [100% Working]
PRTG Network Monitor Crack Latest Version & Serial Key 2025 [100% Working]
saimabibi60507
 
Best Practices for Collaborating with 3D Artists in Mobile Game Development
Best Practices for Collaborating with 3D Artists in Mobile Game DevelopmentBest Practices for Collaborating with 3D Artists in Mobile Game Development
Best Practices for Collaborating with 3D Artists in Mobile Game Development
Juego Studios
 
Get & Download Wondershare Filmora Crack Latest [2025]
Get & Download Wondershare Filmora Crack Latest [2025]Get & Download Wondershare Filmora Crack Latest [2025]
Get & Download Wondershare Filmora Crack Latest [2025]
saniaaftab72555
 
Microsoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdf
Microsoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdfMicrosoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdf
Microsoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdf
TechSoup
 
Exploring Wayland: A Modern Display Server for the Future
Exploring Wayland: A Modern Display Server for the FutureExploring Wayland: A Modern Display Server for the Future
Exploring Wayland: A Modern Display Server for the Future
ICS
 
Apple Logic Pro X Crack FRESH Version 2025
Apple Logic Pro X Crack FRESH Version 2025Apple Logic Pro X Crack FRESH Version 2025
Apple Logic Pro X Crack FRESH Version 2025
fs4635986
 
The Significance of Hardware in Information Systems.pdf
The Significance of Hardware in Information Systems.pdfThe Significance of Hardware in Information Systems.pdf
The Significance of Hardware in Information Systems.pdf
drewplanas10
 
Top 10 Data Cleansing Tools for 2025.pdf
Top 10 Data Cleansing Tools for 2025.pdfTop 10 Data Cleansing Tools for 2025.pdf
Top 10 Data Cleansing Tools for 2025.pdf
AffinityCore
 
Avast Premium Security Crack FREE Latest Version 2025
Avast Premium Security Crack FREE Latest Version 2025Avast Premium Security Crack FREE Latest Version 2025
Avast Premium Security Crack FREE Latest Version 2025
mu394968
 
🌱 Green Grafana 🌱 Essentials_ Data, Visualizations and Plugins.pdf
🌱 Green Grafana 🌱 Essentials_ Data, Visualizations and Plugins.pdf🌱 Green Grafana 🌱 Essentials_ Data, Visualizations and Plugins.pdf
🌱 Green Grafana 🌱 Essentials_ Data, Visualizations and Plugins.pdf
Imma Valls Bernaus
 
FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...
FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...
FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...
Lionel Briand
 
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
Andre Hora
 
Proactive Vulnerability Detection in Source Code Using Graph Neural Networks:...
Proactive Vulnerability Detection in Source Code Using Graph Neural Networks:...Proactive Vulnerability Detection in Source Code Using Graph Neural Networks:...
Proactive Vulnerability Detection in Source Code Using Graph Neural Networks:...
Ranjan Baisak
 
Top 10 Client Portal Software Solutions for 2025.docx
Top 10 Client Portal Software Solutions for 2025.docxTop 10 Client Portal Software Solutions for 2025.docx
Top 10 Client Portal Software Solutions for 2025.docx
Portli
 
Implementing promises with typescripts, step by step
Implementing promises with typescripts, step by stepImplementing promises with typescripts, step by step
Implementing promises with typescripts, step by step
Ran Wahle
 
Exceptional Behaviors: How Frequently Are They Tested? (AST 2025)
Exceptional Behaviors: How Frequently Are They Tested? (AST 2025)Exceptional Behaviors: How Frequently Are They Tested? (AST 2025)
Exceptional Behaviors: How Frequently Are They Tested? (AST 2025)
Andre Hora
 
Kubernetes_101_Zero_to_Platform_Engineer.pptx
Kubernetes_101_Zero_to_Platform_Engineer.pptxKubernetes_101_Zero_to_Platform_Engineer.pptx
Kubernetes_101_Zero_to_Platform_Engineer.pptx
CloudScouts
 
Odoo ERP for Education Management to Streamline Your Education Process
Odoo ERP for Education Management to Streamline Your Education ProcessOdoo ERP for Education Management to Streamline Your Education Process
Odoo ERP for Education Management to Streamline Your Education Process
iVenture Team LLP
 
Cryptocurrency Exchange Script like Binance.pptx
Cryptocurrency Exchange Script like Binance.pptxCryptocurrency Exchange Script like Binance.pptx
Cryptocurrency Exchange Script like Binance.pptx
riyageorge2024
 
Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...
Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...
Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...
Eric D. Schabell
 
PRTG Network Monitor Crack Latest Version & Serial Key 2025 [100% Working]
PRTG Network Monitor Crack Latest Version & Serial Key 2025 [100% Working]PRTG Network Monitor Crack Latest Version & Serial Key 2025 [100% Working]
PRTG Network Monitor Crack Latest Version & Serial Key 2025 [100% Working]
saimabibi60507
 

PostgreSQL 9.4 JSON Types and Operators

  • 1. PostgreSQL 9.4 JSON Types and Operators Pittsburgh PostgreSQL Users Group 2015 December 16 Nicholas Kiraly github.com/nkiraly Twitter @NicholasKiraly [email protected]
  • 2. Introductions github.com/nkiraly Twitter @NicholasKiraly Systems Integration Engineer Interface Systems to Produce New Value Open Source Tools / PostgreSQL / FreeBSD Advocate To play along with today’s examples, vagrant up with https://github.com/nkiraly/koadstation/tree/master/dbdevf2
  • 3. Why should I JSON with PostgreSQL ? Misconception: I need one system of record. But I need to SQL, JSON, and XML so hard! I have to do transforms, parsing, and derivative storage in my implementation to get the job done with a single system of record. Not so! JSON operators allow for expressions in queries and indexes Less round-trips for information querying and selection Streamline and structure your data in one place in your system of record Base your JSON documents on SQL normalized tables you get best of both worlds!
  • 5. JSON vs JSONB Stored as Text Retains Whitespace Retains Key Order Retains Duplicate Keys Index expressions only Binary Hierarchy of Key/Value pairs Whitespace Discarded Last Duplicate Key Wins GIN Index support can be leveraged by contains operators (@> <@ ? ?| ?&)
  • 6. What about HSTORE? PostgreSQL extension For single-depth Key/Value pairs JSON type objects can be nested to N HSTORE only stores strings JSONB uses full range of JSON numbers for element values
  • 7. JSON Operators -> ->> #> #>> @> <@ ? ?| ?&
  • 8. -> Get Object Field '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::j son->2 {"c":"baz"} ->> Get Object Field As Text '{"a":1,"b":2}'::json->>'b' 2 #> Get Object At Specified Path '{"a": {"b":{"c": "foo"}}}'::json#>'{a,b}' {"c": "foo"} #>> Get Object At Specified Path As Text '{"a":[1,2,3],"b":[4,5,6]}'::json#>>'{ a,2}' 3 JSON / JSONB Operators
  • 9. @> Does the left object contain the element on the right? '{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb <@ Is the left element and value contained in the right? '{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb ? Does the field key string exist within the JSON value? '{"a":1, "b":2}'::jsonb ? 'b' ?| Do any of these key strings exist? '{"a":1, "b":2, "c":3}'::jsonb ?| array['b', 'c'] JSONB Contains Operators ?& Do all these key strings exist? '["a", "b"]'::jsonb ?& array['a', 'b']
  • 11. Table JSON Type Usage suchjson=# CREATE TABLE somejson ( id INTEGER, doc JSON ); CREATE TABLE suchjson=# d+ somejson Table "public.somejson" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+----------+--------------+------------- id | integer | | plain | | doc | json | | extended | |
  • 12. Insert JSON Data suchjson=# INSERT INTO somejson VALUES ( 1, '{ "name": "Nicholas Kiraly", "address": { "line1": "5400 City Blvd", "line2": "Apt B", "city": "Pittsburgh", "state": "PA", "zipcode": "15212" } }'); INSERT 0 1
  • 13. Select JSON Data suchjson=# SELECT * FROM somejson ; id | doc ----+-------------------------------- 1 | { + | "name": "Nicholas Kiraly", + | "address": { + | "line1": "5400 City Blvd", + | "line2": "Apt B", + | "city": "Pittsburgh", + | "state": "PA", + | "zipcode": "15212" + | } + | } (1 row)
  • 14. Extract JSON Data suchjson=# SELECT doc->>'address' FROM somejson ; ?column? -------------------------------- { + "line1": "5400 City Blvd",+ "line2": "Apt B", + "city": "Pittsburgh", + "state": "PA", + "zipcode": "15212" + } (1 row)
  • 15. Navigate JSON Data suchjson=# SELECT doc->'address'->>'zipcode' from somejson ; ?column? ---------- 15212 (1 row) suchjson=# SELECT doc->'address'->>'zipcode' = ‘15212’ from somejson ; ?column? ---------- t (1 row)
  • 17. Table JSONB Type Usage suchjson=# CREATE TABLE somejsonb ( id BIGSERIAL, doc JSONB ); CREATE TABLE suchjson=# d+ somejsonb Table "public.somejsonb" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+----------+--------------+------------- id | integer | | plain | | doc | jsonb | | extended | |
  • 18. Insert JSONB Data suchjson=# INSERT INTO somejsonb ( doc ) VALUES ( '{ "name": "Nicholas Kiraly", "address": { "line1": "5400 City Blvd", "line2": "Apt B", "city": "Pittsburgh", "state": "PA", "zipcode": "15212" } }'); INSERT 0 1
  • 19. Select JSONB Data suchjson=# SELECT * FROM somejsonb ; id | doc ----+------------------------------------------------------------------------------- - 1 | {"name": "Nicholas Kiraly", "address": {"city": "Pittsburgh", "line1": "5400 City Blvd", "line2": "Apt B", "state": "PA", "zipcode": "15212"}} (1 row)
  • 20. Extract JSONB Data suchjson=# SELECT doc->>'address' FROM somejsonb ; ?column? ------------------------------------------------------------------------------------ - {"city": "Pittsburgh", "line1": "5400 City Blvd", "line2": "Apt B", "state": "PA", "zipcode": "15212"} (1 row)
  • 21. How many rows have that JSON element? suchjson=# SELECT COUNT(*) FROM somejsonb ; count -------- 101104 suchjson=# SELECT COUNT(*) FROM somejsonb WHERE doc->'address'?'line2'; count ------- 56619
  • 22. JSON Element arrays values suchjson=# CREATE TABLE shopping_lists ( shopping_list_id BIGSERIAL, shopping_list_doc JSONB ); CREATE TABLE suchjson=# INSERT INTO shopping_lists ( shopping_list_doc ) VALUES ( '{ "listName": "Needed supplies", "items": [ "diet shasta", "cheese curls", "mousse" ] }' ); INSERT 0 1
  • 23. Element arrays as result rows suchjson=# SELECT * FROM shopping_lists; shopping_list_id | shopping_list_doc ------------------+----------------------------------------------------------------- 2 | {"items": ["diet shasta", "cheese curls", "mousse"], "listName": "Needed supplies"} (1 row) suchjson=# SELECT jsonb_array_elements_text(shopping_list_doc->'items') AS item FROM shopping_lists; item -------------- diet shasta cheese curls mousse (3 rows)
  • 24. Multiple rows, Element arrays as result rows suchjson=# INSERT INTO shopping_lists ( shopping_list_doc ) VALUES ( '{ "listName": "Running low", "items": [ "grid paper", "cheese curls", "guy fawkes masks" ] }' ); INSERT 0 1 suchjson=# SELECT jsonb_array_elements_text(shopping_list_doc->'items') AS item FROM shopping_lists; item ------------------ diet shasta cheese curls mousse grid paper cheese curls guy fawkes masks (6 rows)
  • 26. Cost of WHERE JSON ->> Expression suchjson=# SELECT COUNT(*) FROM somejson; 100101 suchjson=# SELECT COUNT(*) FROM somejson WHERE (doc->'address'->>'zipcode'::text) = '11100'; 1001 suchjson=# EXPLAIN ANALYZE SELECT * FROM somejson WHERE (doc->'address'- >>'zipcode'::text) = '11100'; QUERY PLAN ------------------------------------------------------------------------------------ Seq Scan on somejson (cost=0.00..4671.77 rows=501 width=36) (actual time=0.039..316.502 rows=1001 loops=1) Filter: (((doc -> 'address'::text) ->> 'zipcode'::text) = '11100'::text) Rows Removed by Filter: 99100 Planning time: 0.093 ms Execution time: 366.303 ms
  • 27. Indexing for WHERE JSON ->> Expression Expressionsuchjson=# CREATE INDEX somejson_zipcode ON somejson ((doc->'address'->>'zipcode'::text)); suchjson=# EXPLAIN ANALYZE SELECT * FROM somejson WHERE (doc->'address'->>'zipcode'::text) = '11100'; QUERY PLAN ------------------------------------------------------------------------------------ Bitmap Heap Scan on somejson (cost=12.18..1317.64 rows=501 width=36) (actual time=0.222..3.256 rows=1001 loops=1) Recheck Cond: (((doc -> 'address'::text) ->> 'zipcode'::text) = '11100'::text) Heap Blocks: exact=1001 -> Bitmap Index Scan on somejson_zipcode (cost=0.00..12.06 rows=501 width=0) (actual time=0.210..0.210 rows=1001 loops=1) Index Cond: (((doc -> 'address'::text) ->> 'zipcode'::text) = '11100'::text) Planning time: 0.186 ms Execution time: 5.214 ms
  • 28. Cost of WHERE ->Element->> Expression suchjson=# SELECT COUNT(*) FROM somejsonb; 101104 suchjson=# EXPLAIN ANALYZE SELECT * FROM somejsonb WHERE (doc->'address'- >>'zipcode'::text) = '11100'; QUERY PLAN ------------------------------------------------------------------------------------ Seq Scan on somejsonb (cost=0.00..4171.32 rows=506 width=159) (actual time=0.033..58.670 rows=1011 loops=1) Filter: (((doc -> 'address'::text) ->> 'zipcode'::text) = '11100'::text) Rows Removed by Filter: 100093 Planning time: 0.134 ms Execution time: 64.235 ms
  • 29. Indexing for WHERE ->Element->> Expression CREATE INDEX somejsonb_zipcode ON somejsonb ((doc->'address'->>'zipcode'::text)); suchjson=# EXPLAIN ANALYZE SELECT * FROM somejsonb WHERE (doc->'address'- >>'zipcode'::text) = '11100'; QUERY PLAN ----------------------------------------------------------------------------------- Bitmap Heap Scan on somejsonb (cost=12.22..1253.10 rows=506 width=159) (actual time=0.440..4.003 rows=1011 loops=1) Recheck Cond: (((doc -> 'address'::text) ->> 'zipcode'::text) = '11100'::text) Heap Blocks: exact=1011 -> Bitmap Index Scan on somejsonb_zipcode (cost=0.00..12.09 rows=506 width=0) (actual time=0.217..0.217 rows=1011 loops=1) Index Cond: (((doc -> 'address'::text) ->> 'zipcode'::text) = '11100'::text) Planning time: 0.113 ms Execution time: 6.161 ms
  • 30. Cost of WHERE @> Contains Operator suchjson=# EXPLAIN ANALYZE SELECT * FROM somejsonb WHERE doc @> '{ "address": { "zipcode":"11100" } }'; QUERY PLAN ------------------------------------------------------------------------------------ - Seq Scan on somejsonb (cost=0.00..3665.80 rows=101 width=159) (actual time=0.019..59.580 rows=1011 loops=1) Filter: (doc @> '{"address": {"zipcode": "11100"}}'::jsonb) Rows Removed by Filter: 100093 Planning time: 0.094 ms Execution time: 64.843 ms
  • 31. Indexing for WHERE @> Contains Operator suchjson=# CREATE INDEX somejsonb_gin ON somejsonb USING gin ( doc jsonb_path_ops); CREATE INDEX suchjson=# EXPLAIN ANALYZE SELECT * FROM somejsonb WHERE doc @> '{ "address": { "zipcode":"11100" } }'; QUERY PLAN ------------------------------------------------------------------------------------ - Bitmap Heap Scan on somejsonb (cost=12.78..349.75 rows=101 width=159) (actual time=0.376..4.644 rows=1011 loops=1) Recheck Cond: (doc @> '{"address": {"zipcode": "11100"}}'::jsonb) Heap Blocks: exact=1011 -> Bitmap Index Scan on somejsonb_gin (cost=0.00..12.76 rows=101 width=0) (actual time=0.271..0.271 rows=1011 loops=1) Index Cond: (doc @> '{"address": {"zipcode": "11100"}}'::jsonb) Planning time: 0.136 ms Execution time: 6.800 ms
  • 32. Index Size Cost Considerations suchjson=# SELECT nspname AS "namespace", relname AS "relation", pg_size_pretty(pg_relation_size(C.oid)) AS "size" FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) WHERE nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast') ORDER BY pg_relation_size(C.oid) DESC; namespace | relation | size -----------+-------------------+------------ public | somejsonb | 19 MB public | somejsonb_zipcode | 2232 kB public | somejsonb_gin | 1680 kB public | somejson | 8192 bytes public | somejsonb_id_seq | 8192 bytes public | posts | 8192 bytes (6 rows)
  • 33. JSON Views SELECT doc FROM jsonview WHERE things ----------------------------- { “formatted”: “data” }
  • 34. Blog Site User Data Model CREATE TABLE users ( user_id varchar(100) PRIMARY KEY, user_name varchar(100) NOT NULL, user_rank integer NOT NULL DEFAULT 10, user_display_name varchar(200) NOT NULL user_profile text );
  • 35. Blog Site Post Data Model CREATE TABLE posts ( post_id varchar(100) PRIMARY KEY, post_date timestamp with time zone, post_summary varchar(200) NOT NULL, post_content text NOT NULL, post_tags varchar(100)[] ); CREATE TABLE posts_read ( post_id varchar(100) REFERENCES posts(post_id), user_id varchar(100) REFERENCES users(user_id), read_date timestamp with time zone NOT NULL, PRIMARY KEY (post_id, user_id) );
  • 36. User Detail JSON View CREATE VIEW users_json AS SELECT users.*, row_to_json(users, TRUE) FROM users ; SELECT * FROM users_json WHERE user_name = 'rsanchez'; -[ RECORD 1 ]-----+--------------------------------------------------- user_id | [email protected] user_name | rsanchez user_rank | 10 user_display_name | Richard Sanchez user_profile | Wubba lubba dub-dub! row_to_json | {"user_id":"[email protected]", | "user_name":"rsanchez", | "user_rank":10, | "user_display_name":"Richard Sanchez", | "user_profile":"Wubba lubba dub-dub!"}
  • 37. Post JSON View blogsite=# CREATE VIEW posts_json AS SELECT posts.*, row_to_json(posts, TRUE) FROM posts ;
  • 38. SELECT FROM Post JSON View blogsite=# SELECT * FROM posts_json WHERE post_id = 'beths-new-bike'; -[ RECORD 1 ]+-------------------------------------------------------------------- post_id | beths-new-bike post_date | 2015-12-15 04:04:37.985041+00 user_id | [email protected] post_summary | My New Bike post_content | I got a new bike last night and it's better than a horse post_tags | {bike,new,suchpedal} row_to_json | {"post_id":"beths-new-bike", | "post_date":"2015-12-15T04:04:37.985041+00:00", | "user_id":"[email protected]", | "post_summary":"My New Bike", | "post_content":"I got a new bike last night and it's better than a horse", | "post_tags":["bike","new","suchpedal"]}
  • 39. Unread Posts JSON View CREATE VIEW unread_posts_json AS -- users that have not read posts SELECT ur.*, row_to_json(ur, TRUE) AS json FROM ( -- select u.user_id so view queries can limit to a specific user's unread posts SELECT u.user_id, p.post_id, p.post_summary, p.post_date FROM users AS u CROSS JOIN posts AS p WHERE NOT EXISTS ( SELECT 1 FROM posts_read WHERE post_id = p.post_id AND user_id = u.user_id ) ) AS ur;
  • 40. Posts Data blogsite=# SELECT * FROM posts; -[ RECORD 1 ]+--------------------------------------------------------- post_id | beths-new-bike post_date | 2015-12-15 05:59:26.634021+00 user_id | [email protected] post_summary | My New Bike post_content | I got a new bike last night and it's better than a horse post_tags | {bike,new,suchpedal} -[ RECORD 2 ]+--------------------------------------------------------- post_id | ricks-new-space-van post_date | 2015-12-15 05:59:26.634021+00 user_id | [email protected] post_summary | New Spaceship post_content | I got a new spaceship last night and -burp- its awesome post_tags | {spaceship,new,interdimensional}
  • 41. Select Morty Unread Posts JSON View blogsite=# -- what posts hasn't Morty read yet? blogsite=# SELECT json FROM unread_posts_json WHERE user_id = '[email protected]'; json --------------------------------------------------------- {"user_id":"[email protected]", + "post_id":"beths-new-bike", + "post_user_id":"[email protected]",+ "post_summary":"My New Bike", + "post_date":"2015-12-15T02:55:59.461635+00:00"} {"user_id":"[email protected]", + "post_id":"ricks-new-space-van", + "post_user_id":"[email protected]",+ "post_summary":"I Got A New Space Van", + "post_date":"2015-12-15T02:55:59.461635+00:00"} (2 rows)
  • 42. Select Rick Unread Posts JSON View blogsite=# -- what posts hasn't Rick read yet? blogsite=# SELECT json FROM unread_posts_json WHERE user_id = '[email protected]'; json ------ (0 rows)
  • 43. Select Beth Unread Posts JSON View blogsite=# -- what posts hasn't Beth read yet? blogsite=# SELECT json FROM unread_posts_json WHERE user_id = '[email protected]'; json --------------------------------------------------------- {"user_id":"[email protected]", + "post_id":"ricks-new-space-van", + "post_user_id":"[email protected]",+ "post_summary":"I Got A New Space Van", + "post_date":"2015-12-15T02:55:59.461635+00:00"} (1 row)
  • 44. Alternate Unread Posts View CREATE VIEW unread_posts_v2_json AS -- users that have not read posts -- alternate version SELECT ur.*, row_to_json(ur, TRUE) AS json FROM ( SELECT posts.post_id, posts.post_date, posts.post_summary, users.user_id -- take the cross product of users and posts FROM users INNER JOIN posts ON ( -- filter out the ones that exist in posts_read (users.user_id, posts.post_id) NOT IN (SELECT user_id, post_id FROM posts_read) ) ) AS ur;
  • 45. Common Q&A Topic for PostgreSQL 9.4 No in-place element editing in 9.4 JSON structures must be rebuilt to update element values jsonb_set() in 9.5 to replace entire sections Append children elements by the same name to overwrite existing values in 9.4 Regenerate / reselect entire JSON structure
  • 47. Questions ? Answers ! Feedbacks PostgreSQL 9.4 JSON Types and Operators http://www.meetup.com/Pittsburgh-PostgreSQL-Users-Group Check Out @lfgpgh http://lfgpgh.com Nicholas Kiraly github.com/nkiraly Twitter @NicholasKiraly [email protected]

Editor's Notes

  • #3: I am a Systems Integration Engineer. To me that means that I take different systems written in different ways with different technology, connect these systems to produce new value with the correlated data or through the interaction of those previously separate systems. Doing this means knowing what technology you already have or you may be planning to deploy can do for you. I am also an advocate for several open source projects and platforms.
  • #4: One big aspect that a lot of engineers face is how to talk SQL, JSON, XML, et al to one data system of record efficiently with minimized implementation and maintenance overhead. A great platform to accomplish this is with PostgreSQL. You can transform, select specific sections of data, and use JSON data in expressions in database queries without any round trips to your application implementation layer. REVIEW SLIDE The goal of this particular talk is to inform you of the features PostgreSQL 9.4 JSON types and operators. These features are an efficient and convenient way to store, query, and update JSON data structures that your applications need to use.
  • #5: As of PostgreSQL 9.4, there are two JSON types to be aware of that may apply to your implementation needs: JSON and JSONB
  • #6: REVIEW SLIDE GIN stands for Generalized Inverted Index. GIN is designed for handling cases where the items to be indexed are composite values, and the queries to be handled by the index need to search for element values that appear within the composite items. For example, the items could be documents, and the queries could be searches for documents containing specific words.
  • #7: Some of you might be saying, hey bruh, what about HSTORE ? REVIEW SLIDE
  • #8: If you are going to use JSON types, then you should know what the JSON operators are and how you can use them in value expressions and WHERE clauses.
  • #9: When an object is returned, it is either JSON or JSONB - the same as the left hand operand. Hash arrow #> operators take array-of-string arguments. Notice the object value at array-of-string path A COMMA TWO is 3 and not 2, as object elements are zero indexed.
  • #10: JSONB types have additional operators for comparing their fields and sets of those fields.
  • #12: We see that the doc column Storage Strategy is extended meaning it allows for both compression and out-of-line storage if the row is still too big to fit on an 8k page. This is explained in more detail in the PostgreSQL documentation under TOAST - an acronym for The Oversized-Attribute Storage Technique.
  • #14: An exact copy of the JSON inserted has been stored. REVIEW SLIDE We can still extract elements of the data with JSON operators such as ->> dash arrow arrow.
  • #15: The dash arrow arrow operator says, within the doc, look up the field and return it as text. REVIEW SLIDE You typically do not want to do this unless you know you do not plan to do anymore processing or selection of the JSON data such as to pipe the JSON data it to the user’s browser for use in a widget.
  • #16: There is also dash arrow which doesn’t convert the field to text and leaves it as a JSON element. This can be used to navigate JSON objects and subsections such as the address element of a greater JSON document containing a person’s details. REVIEW SLIDE
  • #18: Now let’s create a table with a column of type JSONB
  • #19: Let’s insert the same JSON document into the JSONB table.
  • #20: The data is returned with normalized formatting, white space is gone. REVIEW SLIDE We can still extract elements of the data with JSON operators such as dash arrow arrow ->>.
  • #21: REVIEW SLIDE The JSON object select is returned with normalized formatting, no white space of the address element is returned.
  • #22: We can use question mark operator ? does field key exist to select rows that have a specific element key. I know that my sample data only has line2 for address about half the time. So how do I get rows that only have line2 specified ? REVIEW SLIDE
  • #23: What if we have data as a JSON array and we need to use it as a row result set? Consider this example where we have shopping lists as JSONB documents and the items to purchase are stored as a JSON array.
  • #24: We can expand JSON arrays as rows with jsonb_array_elements_text() for display in a checklist or other item iterator collection.
  • #25: What if we have another row and query the table resulting in more than one row matching? jsonb_array_elements_text() has collected all rows’ item arrays and turned them into a result set of 6 rows. There are two cheese curls value rows as both shopping lists contained that value in the items array. What if I limit 1 SELECT distinct on ( item ) shopping_list_id, jsonb_array_elements_text(shopping_list_doc->'items') AS item, shopping_list_doc->'listName' as name FROM shopping_lists ;
  • #27: For the somejson table with 100101 rows, the cost is 0 startup cost, and 4671.77 to retrieve every matching row, with an execution time of 366.303 ms
  • #28: Using a JSON text expression index for zip code, the cost is now 12.18 startup and 1317.64 cost to retrieve all rows instead of 4171.32 units, with execution time down to 5.214 ms from 366.303 ms - a big execution time savings.
  • #29: On a the JSONB version of the address document table with 10104 rows, the cost is 0 startup cost, and 4171.32 to retrieve every matching row, with an execution time of 64.235 ms JSONB query plans in this example are already measuring faster without an explicit zipcode expression index.
  • #30: What if we add the JSON selection value expression index, the same as we use in the where clause, Cost has changed from 0 startup cost, 4171.32 to retrieve all matching rows with 64.235 ms execution time down to 12.22 startup cost, all row retrieval cost at 1253.10 units which is over a one thirds savings at 1265.32 total cost, running 10 times faster at 6.161 ms execution time Less planner cost than JSON column expression index at 1329.82 units for the somejson table, but slower than 5.214 ms
  • #31: What about if we need contains expression efficiency? Generalized Inverted Indexes and the JSON Contains Operators are often faster especially in situations with complex JSON documents and many rows. With the AT ARROW @> left contains right operator, we already see the cost to find the same rows with zipcode 11100 has gone from 4171.32 to 3665.80 with no startup cost, 64.843 ms execution time You might be asking, can we make that base line more efficient with an index?
  • #32: The answer is - ussuuuuaaaally! We can add an index to support our where clause that is using a @> left contains right operator on the JSON document for selection. Let’s say we know that our application is usually doing WHERE clauses with the left contains right operator for zipcode match clauses, We specify a GIN index with the jsonb_path_ops operator class to limit the index to the @> left contains right operator and its inverse. This makes it a more size efficient index compared to creating a GIN index without the jsonb_path_ops operator class specifier. This takes our cost from 0 startup and 3665.80 for full retrieval down to 12.78 startup with only 349.75 cost to retrieve all rows. That’s a total cost of only 362.53 to get all matching rows for the 11100 test zipcode in 6.800 ms. That’s 10 fold query cost and time savings - the best overall as measured in our example index variants.
  • #33: And now are you asking yourself - in this particular case did we just prove that a string element selection expression is faster than a Generalized Inverted Index ? Yes we did - but at what cost! AT WHAT COST! Remember, the somejsonb table has 101104 rows in it, taking up 19 MB of space. The _zipcode index is 2232 kB in size and only indexes the value of the zipcode selection expression. The _gin index is 1680 kB and indexes all json paths to their values for use by the contains operators. So the GIN method is half a millisecond slower but takes up only 75% of the space, and can be used by contains operators for any path value expression comparisons for the whole JSON document. Optimization through indexing all depends what your application needs to query efficiently.
  • #34: The examples so far have been contrived to give you a sense of how JSON data types and operators work. If your task is to intake JSON documents and process them, then those examples certainly apply. However, I also want to make sure I review something important for your implementations: And that is that I do NOT recommend JSON for primary storage of application data. For system of record storage, I advocate to use normalized relational design whenever possible. That’s not to say that PostgreSQL should not be the means by which you transform your data to JSON, so let’s go through an example of how you might do that.
  • #35: This application database has users, and users post blog entries, and interested users come read them, and we keep track of that. This is the basic users table with user id, name, rank, display name, and profile. And here ... ADVANCE SLIDE
  • #36: … is the post data model and how we keep track of how has read what posts. For the sake of this example, user_id’s are emails and post_id’s are slugs so we can readily digest the data without a reference sheet. REVIEW SLIDE Let’s go see how we can create JSON views of this data for use by the blog application presentation layer.
  • #37: This is what a view might look like to select user details as a JSON document.
  • #38: This is what a view might look like to select post details as a JSON document.
  • #39: And a select from that post JSON view.
  • #40: Those are basic views. How about a view of posts that a specific user has not read yet? REVIEW SLIDE Let’s try this view.
  • #41: There are two posts in the system, one by Beth and one by Rick.
  • #42: Here are the posts that Morty has not read yet. He has not read any of the two posts in the system.
  • #43: Here are the posts that Rick has read. He has read all two posts in the system.
  • #44: Here are the posts that Beth has not read. She has read her own post. Rick’s new space van post is still unread to Beth.
  • #45: What if you need to optimize or determine which view is faster? Consider this alternate view definition that uses INNER JOIN ON NOT IN instead of CROSS JOIN WHERE NOT EXISTS EXPLAIN ANALYZE IN TERMINAL CREATE VIEW unread_posts_v2_json AS -- users that have not read posts -- alternate version SELECT ur.*, row_to_json(ur, TRUE) AS json FROM ( SELECT posts.post_id, posts.post_date, posts.post_summary, users.user_id -- take the cross product of users and posts FROM users INNER JOIN posts ON ( -- filter out the ones that exist in posts_read (users.user_id, posts.post_id) NOT IN (SELECT user_id, post_id FROM posts_read) ) ) AS ur; SELECT COUNT(*) FROM posts; SELECT COUNT(*) FROM posts_read; SELECT COUNT(*) FROM unread_posts_json WHERE user_id = '[email protected]'; EXPLAIN ANALYZE SELECT json FROM unread_posts_json WHERE user_id = '[email protected]'; EXPLAIN ANALYZE SELECT json FROM unread_posts_v2_json WHERE user_id = '[email protected]'; The query planner costs are similar for the inner loops, but lower for the hash anti join versus the loop, this is because some rows can be dropped during first pass filtering. This query profiles better, and may be the better choice to go live with. Need to do more testing to be sure.
  • #46: There is one limitation I know some of you may be aware of that I would like to address. And that is that There is no in-place editing of JSON elements in 9.4 In PostgreSQL 9.5, the jsonb_set() function allows you to replace sections of a JSON document in place. Look into jsonb_set() usage for more details on this. In 9.4, one approach to do in-place updating is to append child elements with updated values and allow the storage behavior of JSONB last-element-wins behavior to update your element values. There is also always the rebuild the JSON document approach where you read and modify JSON document and overwrite the previous version entirely.
  • #47: Can you foreign key JSON documents to another table? (check this) You can for anything that supports a GIN index, so you can with JSONB