..

PostgreSQL + JSON Data

PostgreSQL 9.2 added a native JSON data type, but didn’t add much else. You’ve got three options if you actually want to do something with it:

  • Wait for PostgreSQL 9.3 (or use the beta) Released
  • Use the plv8 extension. Valid option, but more DIY (you’ll have to define your own functions)
  • Use the json_enhancements extension, which backports the new JSON functionality in 9.3 to 9.2

Table Schema

CREATE TABLE buku (
    id integer NOT NULL,
    data json
);

Insert Data

INSERT INTO buku VALUES (1, '{
    "tajuk": "Ayam Goreng",
    "penulis": {
        "nama_pena": "Bob Ayam",
        "nama_sebenar": "Bob Suka Ayam"
    },
    "info": {
        "diterbitkan": "20-03-2015",
        "sinopsis": "bob suka makan ayam, hari-hari dia makan ayam"
    }
}');

INSERT INTO buku VALUES (2, '{
    "tajuk": "Kambing Golek",
    "penulis": {
        "nama_pena": "Abu Al-Kambing",
        "nama_sebenar": "Abu"
    },
    "info": {
        "diterbitkan": "25-01-2015",
        "sinopsis": "abu suka tengok kambing, hari-hari beliau terbayang kambing golek"
    }
}');

INSERT INTO buku VALUES (3, '{
    "tajuk": "Cicak Terbang",
    "penulis": {
        "nama_pena": "Cicakman",
        "nama_sebenar": "Cicakak"
    },
    "info": {
        "diterbitkan": "29-01-2015",
        "sinopsis": "Cicak yang boleh terbang"
    }
}');

Selecting

SELECT id, data->>'tajuk' as tajuk FROM buku;
id |      name
----+-----------------
  1 | Ayam Goreng
  2 | Kambing Goreng
  3 | Cicak Terbang

The -> operator returns the original JSON type (which might be an object), whereas -» returns text. You can use the -> to return a nested object and thus chain the operators:

SELECT id, data->'penulis'->>'nama_pena' as nama_pena FROM buku;

 id | nama_pena
----+-------------------
  1 | Bob Ayam
  2 | Abu Al-Kambing
  3 | Cicakman

Searching/Filtering You can select rows based on a value inside your JSON:

SELECT * FROM buku WHERE data->>'tajuk' = 'Cicak Terbang';

 id |                                         data
----+---------------------------------------------------------------------------------------
  1 | '{"tajuk": "Cicak Terbang","penulis": {"nama_pena": "Cicakman","nama_sebenar": "Cicakak"},"info": {"diterbitkan": "29-01-2015","sinopsis": "Cicak yang boleh terbang"}}'

Also with nasted JSON object

SELECT * FROM buku WHERE data->'penulis'->>'nama_pena' = 'Cicakman';

 id |                                         data
----+---------------------------------------------------------------------------------------
  1 | '{"tajuk": "Cicak Terbang","penulis": {"nama_pena": "Cicakman","nama_sebenar": "Cicakak"},"info": {"diterbitkan": "29-01-2015","sinopsis": "Cicak yang boleh terbang"}}' 

Indexing You can add indexes on any of these using PostgreSQL’s expression indexes, which means you can even add unique constraints based on your nested JSON data:

CREATE UNIQUE INDEX buku_penulis_nama_pena ON buku ((data->'penulis'->>'nama_pena'));

Cheers.