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

More Related Content

What's hot

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
 
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 FrameworkMongoDB
 

What's hot (20)

MongoDB - Aggregation Pipeline
MongoDB - Aggregation PipelineMongoDB - Aggregation Pipeline
MongoDB - Aggregation Pipeline
 
Full Text Search In PostgreSQL
Full Text Search In PostgreSQLFull Text Search In PostgreSQL
Full Text Search In PostgreSQL
 
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
 
Latinoware
LatinowareLatinoware
Latinoware
 
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
 
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
 
Webinar: Index Tuning and Evaluation
Webinar: Index Tuning and EvaluationWebinar: Index Tuning and Evaluation
Webinar: Index Tuning and Evaluation
 
Indexing and Query Optimizer (Mongo Austin)
Indexing and Query Optimizer (Mongo Austin)Indexing and Query Optimizer (Mongo Austin)
Indexing and Query Optimizer (Mongo Austin)
 
The Aggregation Framework
The Aggregation FrameworkThe Aggregation Framework
The Aggregation Framework
 
Fast querying indexing for performance (4)
Fast querying   indexing for performance (4)Fast querying   indexing for performance (4)
Fast querying indexing for performance (4)
 
Webinar: Exploring the Aggregation Framework
Webinar: Exploring the Aggregation FrameworkWebinar: Exploring the Aggregation Framework
Webinar: Exploring the Aggregation Framework
 
Indexing with MongoDB
Indexing with MongoDBIndexing with MongoDB
Indexing with MongoDB
 
MongoDB and Indexes - MUG Denver - 20160329
MongoDB and Indexes - MUG Denver - 20160329MongoDB and Indexes - MUG Denver - 20160329
MongoDB and Indexes - MUG Denver - 20160329
 
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...
 
Database Wizardry for Legacy Applications
Database Wizardry for Legacy ApplicationsDatabase Wizardry for Legacy Applications
Database Wizardry for Legacy Applications
 
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
 
Indexing and Performance Tuning
Indexing and Performance TuningIndexing and Performance Tuning
Indexing and Performance Tuning
 
MongoDB Aggregation
MongoDB Aggregation MongoDB Aggregation
MongoDB Aggregation
 
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
 
The Aggregation Framework
The Aggregation FrameworkThe Aggregation Framework
The Aggregation Framework
 

Viewers also liked

Matt Misiak 2016
Matt Misiak 2016Matt Misiak 2016
Matt Misiak 2016Matt 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
 

Viewers also liked (8)

Matt Misiak 2016
Matt Misiak 2016Matt Misiak 2016
Matt Misiak 2016
 
Hirschsprungs disease
Hirschsprungs disease Hirschsprungs disease
Hirschsprungs disease
 
Aula virtual
Aula virtualAula virtual
Aula virtual
 
Reserva ecológica el ángel
Reserva ecológica el ángelReserva ecológica el ángel
Reserva ecológica el ángel
 
PostgreSQL 9.5 Foreign Data Wrappers
PostgreSQL 9.5 Foreign Data WrappersPostgreSQL 9.5 Foreign Data Wrappers
PostgreSQL 9.5 Foreign Data Wrappers
 
Banco de preguntas
Banco de preguntasBanco de preguntas
Banco de preguntas
 
Presentación victoria_yovicha
Presentación victoria_yovichaPresentación victoria_yovicha
Presentación victoria_yovicha
 
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
 

Similar to PostgreSQL 9.4 JSON Types and Operators

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 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
 
Lecture 40 1
Lecture 40 1Lecture 40 1
Lecture 40 1
patib5
 

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, Олег Бартунов, Александ...
 
Json in Postgres - the Roadmap
 Json in Postgres - the Roadmap Json in Postgres - the Roadmap
Json in Postgres - the Roadmap
 
Postgres vs Mongo / Олег Бартунов (Postgres Professional)
Postgres vs Mongo / Олег Бартунов (Postgres Professional)Postgres vs Mongo / Олег Бартунов (Postgres Professional)
Postgres vs Mongo / Олег Бартунов (Postgres Professional)
 
JSON and the Oracle Database
JSON and the Oracle DatabaseJSON and the Oracle Database
JSON and the Oracle Database
 
Postgres Performance for Humans
Postgres Performance for HumansPostgres Performance for Humans
Postgres Performance for Humans
 
Power JSON with PostgreSQL
Power JSON with PostgreSQLPower JSON with PostgreSQL
Power JSON with PostgreSQL
 
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
 
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
 
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
 
PG Day'14 Russia, Работа со слабо-структурированными данными в PostgreSQL, Ол...
PG Day'14 Russia, Работа со слабо-структурированными данными в PostgreSQL, Ол...PG Day'14 Russia, Работа со слабо-структурированными данными в PostgreSQL, Ол...
PG Day'14 Russia, Работа со слабо-структурированными данными в PostgreSQL, Ол...
 
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 :: ...
 
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
 
NoSQL Best Practices for PostgreSQL / Дмитрий Долгов (Mindojo)
NoSQL Best Practices for PostgreSQL / Дмитрий Долгов (Mindojo)NoSQL Best Practices for PostgreSQL / Дмитрий Долгов (Mindojo)
NoSQL Best Practices for PostgreSQL / Дмитрий Долгов (Mindojo)
 
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
 
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
 
Deep dive to PostgreSQL Indexes
Deep dive to PostgreSQL IndexesDeep dive to PostgreSQL Indexes
Deep dive to PostgreSQL Indexes
 
lecture_40_1.pptx
lecture_40_1.pptxlecture_40_1.pptx
lecture_40_1.pptx
 
lecture_40_1.ppt
lecture_40_1.pptlecture_40_1.ppt
lecture_40_1.ppt
 
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...
 
Lecture 40 1
Lecture 40 1Lecture 40 1
Lecture 40 1
 

Recently uploaded

How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
Globus
 
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdfEnhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Jay Das
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
Matt Welsh
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
Philip Schwarz
 
Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
NYGGS Automation Suite
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
Max Andersen
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns
 
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.ILBeyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Natan Silnitsky
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
abdulrafaychaudhry
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
Google
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Globus
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Anthony Dahanne
 
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Globus
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownload
vrstrong314
 
Using IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New ZealandUsing IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New Zealand
IES VE
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
Fermin Galan
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
Globus
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
Adele Miller
 
Graphic Design Crash Course for beginners
Graphic Design Crash Course for beginnersGraphic Design Crash Course for beginners
Graphic Design Crash Course for beginners
e20449
 
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus
 

Recently uploaded (20)

How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
 
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdfEnhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
 
Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
 
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.ILBeyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
 
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownload
 
Using IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New ZealandUsing IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New Zealand
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
 
Graphic Design Crash Course for beginners
Graphic Design Crash Course for beginnersGraphic Design Crash Course for beginners
Graphic Design Crash Course for beginners
 
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024
 

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 kiraly.nicholas@gmail.com
  • 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 | 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!"}
  • 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 | 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"]}
  • 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 | 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}
  • 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 = '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)
  • 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 = 'rick.sanchez@potp.com'; 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 = '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)
  • 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 kiraly.nicholas@gmail.com

Editor's Notes

  1. 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.
  2. 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.
  3. As of PostgreSQL 9.4, there are two JSON types to be aware of that may apply to your implementation needs: JSON and JSONB
  4. 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.
  5. Some of you might be saying, hey bruh, what about HSTORE ? REVIEW SLIDE
  6. 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.
  7. 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.
  8. JSONB types have additional operators for comparing their fields and sets of those fields.
  9. 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.
  10. 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.
  11. 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.
  12. 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
  13. Now let’s create a table with a column of type JSONB
  14. Let’s insert the same JSON document into the JSONB table.
  15. 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 ->>.
  16. REVIEW SLIDE The JSON object select is returned with normalized formatting, no white space of the address element is returned.
  17. 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
  18. 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.
  19. We can expand JSON arrays as rows with jsonb_array_elements_text() for display in a checklist or other item iterator collection.
  20. 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 ;
  21. 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
  22. 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.
  23. 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.
  24. 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
  25. 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?
  26. 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.
  27. 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.
  28. 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.
  29. 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
  30. … 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.
  31. This is what a view might look like to select user details as a JSON document.
  32. This is what a view might look like to select post details as a JSON document.
  33. And a select from that post JSON view.
  34. 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.
  35. There are two posts in the system, one by Beth and one by Rick.
  36. Here are the posts that Morty has not read yet. He has not read any of the two posts in the system.
  37. Here are the posts that Rick has read. He has read all two posts in the system.
  38. 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.
  39. 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 = 'beth.smith@rr.com'; EXPLAIN ANALYZE SELECT json FROM unread_posts_json WHERE user_id = 'beth.smith@rr.com'; EXPLAIN ANALYZE SELECT json FROM unread_posts_v2_json WHERE user_id = 'beth.smith@rr.com'; 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.
  40. 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.
  41. 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