通过json字段查询Postgres 9.3非常棒.但是我找不到更新json对象的正式方法,为此我使用plpythonu编写的内部函数基于之前的帖子(如何修改新的PostgreSQL JSON数据类型中的字段?):
CREATE OR REPLACE FUNCTION json_update(data json, key text, value json) RETURNS json AS $BODY$ from json import loads, dumps if key is None: return data js = loads(data) js[key] = value return dumps(js) $BODY$ LANGUAGE plpythonu VOLATILE
当我的json更新保持扁平和简单时,它的效果非常好.假设"聊天"是在"GO_SESSION"表中提交的json类型,并包含{"a":"1","b":"2"},以下代码将更改"b"值并将"chat"更改为是{"a":"1","b":"5"}
update "GO_SESSION" set chat=json_update(chat,'b','5') where id=3
问题是当我试图给'b'另一个对象而不是一个简单的值时:
update "GO_SESSION" set chat=json_update(chat,'b','{"name":"steve"}') where id=3
数据库中的结果是'b'包含转义字符串而不是真正的json对象:
{"a":"1","b":"{\"name \":\"steve \"}"}
我已经尝试了不同的方法来unescape或转储我的json以保持'b'为对象,但找不到解决方案.
谢谢
不需要eval
.您的问题是您没有将值解码为json对象.
CREATE OR REPLACE FUNCTION json_update(data json, key text, value json) RETURNS json AS $BODY$ from json import loads, dumps if key is None: return data js = loads(data) # you must decode 'value' with loads too: js[key] = loads(value) return dumps(js) $BODY$ LANGUAGE plpythonu VOLATILE; postgres=# SELECT json_update('{"a":1}', 'a', '{"innerkey":"innervalue"}'); json_update ----------------------------------- {"a": {"innerkey": "innervalue"}} (1 row)
不仅如此,使用eval
解码json
是危险和不可靠的.这是不可靠的,因为json
不是Python,它恰好在很多时候都有点像它.这是不安全的,因为你永远不知道你的评价是什么.在这种情况下,你很大程度上受PostgreSQL的json解析器保护:
postgres=# SELECT json_update( postgres(# '{"a":1}', postgres(# 'a', postgres(# '__import__(''shutil'').rmtree(''/glad_this_is_not_just_root'')' postgres(# ); ERROR: invalid input syntax for type json LINE 4: '__import__(''shutil'').rmtree(''/glad_this_is_not_... ^ DETAIL: Token "__import__" is invalid. CONTEXT: JSON data, line 1: __import__...
......但是如果有人能够eval
利用这个漏洞,我将不会感到惊讶.所以这里的教训是:不要使用eval
.