PostgreSQL 9.2のJSON型

今日はPostgreSQL 9.2からサポートされたJSON型について試してみることにする。

パース処理

まずは、JSON文字列をJSON型にCastしてみる。

test=# SELECT '{"key1":"val1","key2":"val2"}'::json;
             json
-------------------------------
 {"key1":"val1","key2":"val2"}
(1 row)

test=# SELECT '{"key1":"val1","key2":["val2-1","val2-2"]}'::json;
                    json
--------------------------------------------
 {"key1":"val1","key2":["val2-1","val2-2"]}
(1 row)

test=# SELECT '{"key1":"val1","key2":{"key2-1":"val2-1","key2-2":["val2-2-1","val2-2-2"]}}'::json;
                                    json
-----------------------------------------------------------------------------
 {"key1":"val1","key2":{"key2-1":"val2-1","key2-2":["val2-2-1","val2-2-2"]}}
(1 row)

特に問題はなさそう。配列もオブジェクトのネストも対応している。

test=# SELECT '{"key1":"値1","key2":"val2"}'::json;
ERROR:  invalid input syntax for type json
LINE 1: SELECT '{"key1":"値1","key2":"val2"}'::json;
               ^
DETAIL:  line 1: Character "▒" must be escaped.
test=# SELECT '{"キー1":"val1","key2":"val2"}'::json;
ERROR:  invalid input syntax for type json
LINE 1: SELECT '{"キー1":"val1","key2":"val2"}'::json;
               ^
DETAIL:  line 1: Character "▒" must be escaped.
test=#

日本語に関しては、キーにも値にも指定するとパースに失敗する・・・。日本語をサポートしていない仕様のか?いやいや、そんなことはないはず。このtestというデータベース自体はUTF8エンコーディングのはずなのに。上記のSELECT文もUTF8のキャラクタしか含んでいないから、パース出来てもいいはずなのだが。

$ psql -l
                          List of databases
   Name    | Owner  | Encoding | Collate | Ctype | Access privileges
-----------+--------+----------+---------+-------+-------------------
 postgres  | harada | UTF8     | C       | C     |
 template0 | harada | UTF8     | C       | C     | =c/harada        +
           |        |          |         |       | harada=CTc/harada
 template1 | harada | UTF8     | C       | C     | =c/harada        +
           |        |          |         |       | harada=CTc/harada
 test      | harada | UTF8     | C       | C     |
(4 rows)

$

これは、まだbeta版ってこともあるし、やっぱりバグってことなのかな。明後日のJPUGの勉強会のときに知ってそうな人に聞いてみよう。

JSON関数

9.2では残念ながらJSON関連の関数は、ほとんどサポートされていない。サポートされているのは、配列→JSON文字列変換の関数(array_to_json)と、行型→JSON文字列変換(row_to_json)の関数のみ。

test=# SELECT ARRAY[1, 10, 100];
   array
------------
 {1,10,100}
(1 row)

test=# SELECT array_to_json(ARRAY[1, 10, 100]);
 array_to_json
---------------
 [1,10,100]
(1 row)

test=# SELECT ROW(1, 'aaa', now());
                   row
-----------------------------------------
 (1,aaa,"2012-05-24 19:55:12.559679+09")
(1 row)

test=# SELECT row_to_json(ROW(1, 'aaa', now()));
                       row_to_json
----------------------------------------------------------
 {"f1":1,"f2":"aaa","f3":"2012-05-24 19:55:26.783458+09"}
(1 row)

test=#

行コンストラクタの結果をrow_to_json()に渡すとキーが勝手に付与されるのか。ちょっとこの挙動は気持ちが悪い気がする。
複合型を作って、その複合型にcastした結果をrow_to_json()に渡すと、複合型に記述したカラム名をキーにはしてくれるようだが・・・。

test=# CREATE TYPE foo_type AS (id int, data text, ts timestamp);
CREATE TYPE
test=# SELECT row_to_json(ROW(1, 'aaa', now())::foo_type);
                       row_to_json
---------------------------------------------------------
 {"id":1,"data":"aaa","ts":"2012-05-24 20:03:46.758499"}
(1 row)

test=#

今日はここまで。

これから試したいこと

今日はここまでと書いたけど、素のPostgreSQLのままだとこのくらいしか検証するものがないような気がする。

  • JSON文字列内を評価する関数がないので、どうにか評価する方法を考えたい。
    • 特定のキー名を含むJSONデータだけとりたい。
    • 特定のキーと値の間での比較演算をしたい。
      • これが出来れば関数インデックスと組み合わせて、PostgreSQLでなんちゃてNative-JSONデータベースみたいなことも出来るのでは。
    • XPathっぽいJSONアクセス言語の組み込み。
      • そこまでやるならXML型を使えば?というツッコミもあるだろうけど。
  • これを使ってどういうアプリケーションが作れるのか。

このへんをこれからしばらく、ゆるゆると試してみようかと。