はじまる

適当な事を適当に書く

文字列として保存した PostgreSQL の JSON を Python でも JSON として扱う

はじめに

コーナーケースすぎるけど下記のようなケースです。

  • Python プログラムから直接PostgreSQLに接続するのでなく、Postgres のJSON配列の値を、ほかのデータベースのテキスト型の列か、ファイルなどに、文字列、テキストとして保存する
  • Pythonからはその保存されたデータを読み込んで、PythonJSONとして扱いたい

PostgreSQL

Postgres あるテーブルからデータをJSON 型で抽出するときの小ネタ - はじまる で使った Animals テーブルをまた利用します。

SELECT * FROM Animals;
 id    name   age   kind  
 1    Mickey   5   Mouse
 2    Snoopy   3   Dog
 3    Kitty   3   Cat

これを array_agg などでJSONを格納した配列に変換します。

WITH 
AnimalJSON AS (
    SELECT
        id,
        (
            select
                row_to_json(_)
            from
                (select name, age, kind) as _
        ) as attributes
    FROM
        Animals
)
SELECT
    array_agg(attributes)
FROM
    AnimalJSON
array_agg
{"{\"name\":\"Mickey\",\"age\":5,\"kind\":\"Mouse\"}","{\"name\":\"Snoopy\",\"age\":3,\"kind\":\"Dog\"}","{\"name\":\"Kitty\",\"age\":3,\"kind\":\"Cat\"}"}

この値が適当なデータストアに保存されており、それをPythonで扱いたい時の話です。

Python

上記の array_agg の結果が、文字列として格納されている状態です。Python から読み取り、 str 型の変数 string に入力されているとします。

print(string)
>>>{"{\"name\":\"Mickey\",\"age\":5,\"kind\":\"Mouse\"}","{\"name\":\"Snoopy\",\"age\":3,\"kind\":\"Dog\"}","{\"name\":\"Kitty\",\"age\":3,\"kind\":\"Cat\"}"}

print(repr(string))
>>>'{"{\\"name\\":\\"Mickey\\",\\"age\\":5,\\"kind\\":\\"Mouse\\"}","{\\"name\\":\\"Snoopy\\",\\"age\\":3,\\"kind\\":\\"Dog\\"}","{\\"name\\":\\"Kitty\\",\\"age\\":3,\\"kind\\":\\"Cat\\"}"}'

この string をどうPython での JSONに変えていくかですが、結論としては下記のようなアプローチがいいかと感じました。

  1. str から set に変換する
  2. set から JSON に変換する

まず eval() を使うことで、str から set に型変換します。

>>> string = repr(string)
>>> type(string)
<class 'str'>
>>> eval(string)
{'{"name":"Kitty","age":3,"kind":"Cat"}', '{"name":"Snoopy","age":3,"kind":"Dog"}', '{"name":"Mickey","age":5,"kind":"Mouse"}'}
>>> type(eval(string))
<class 'set'>

ここで、配列の要素はまだ文字列になっています。これらの文字列を json.loads()JSONとしてパースします。

>>> new_list = []
>>> if type(eval(string)) == set:
...   for i in eval(string):
...     item = json.loads(i)
...     new_list.append(item)
... 
>>> new_list
[{'name': 'Kitty', 'age': 3, 'kind': 'Cat'}, {'name': 'Snoopy', 'age': 3, 'kind': 'Dog'}, {'name': 'Mickey', 'age': 5, 'kind': 'Mouse'}]

これでようやくPostgresでの JSONPython でも同様のJSONとして扱えるようになりました。