Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 更新Postgres中的json字段_Python_Json_Postgresql - Fatal编程技术网

Python 更新Postgres中的json字段

Python 更新Postgres中的json字段,python,json,postgresql,Python,Json,Postgresql,通过json字段查询Postgres9.3真的很棒。 但是,我找不到一种正式的方法来更新json对象,为此,我使用了一个基于上一篇文章()的内部函数,该函数是用plpythonu编写的: 当我的json更新保持平坦和简单时,它工作得非常好。假设“chat”是“GO_SESSION”表中的json类型,包含{“a”:“1”,“b”:“2”},以下代码将更改'b'值,并将“chat”变为{“a”:“1”,“b”:“5”} update "GO_SESSION" set chat=json_updat

通过json字段查询Postgres9.3真的很棒。 但是,我找不到一种正式的方法来更新json对象,为此,我使用了一个基于上一篇文章()的内部函数,该函数是用plpythonu编写的:

当我的json更新保持平坦和简单时,它工作得非常好。假设“chat”是“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
问题是,当我试图分配另一个对象而不是一个简单的值时:

update "GO_SESSION" set chat=json_update(chat,'b','{"name":"steve"}') where id=3
数据库中的结果是'b'包含转义字符串,而不是真正的json对象:

{“a”:“1”,“b”:“{\“name\”:\“steve\”}”}

update "GO_SESSION" set chat=json_update(chat,'b','5') where id=3
我尝试了不同的方法来取消浏览或转储json,以保持“b”是一个对象,但找不到解决方案


谢谢

解决了

上面的plpythonu函数的问题在于,无论它实际上是一个复杂的json对象,它都与作为字符串的“value”相关。解决此问题的关键是在值周围添加eval()

js[key] = eval(value)

这样,json字符串(在本例中称为“value”)将其外部的双引号“{…}”松开,并成为一个对象。

No
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,它只是在很多时候计算起来有点像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
漏洞逃过这一关,我一点也不会感到惊讶。因此,这里的教训是:对于想要plv8(可在Heroku等服务上使用的可信语言)的人,不要使用
eval

。我经常需要迁移或更新json blob,直接在db上运行查询要比下载所有数据、转换数据然后发布更新快得多

CREATE EXTENSION plv8;
CREATE OR REPLACE FUNCTION json_replace_string(obj json, path text, value text, force boolean)
RETURNS json AS $$
if (value === null && !force) {
  return obj;
}
var nestedRe = /(\.|\[)/;
var scrub = /]/g;
path = path.replace(scrub, '');
var pathBits = path.split(nestedRe);
var len = pathBits.length;
var layer = obj;
for (var i = 0; i < len; i += 2) {
  if (layer === null || layer === undefined) return obj;
  var key = pathBits[i];
  if (key === '') continue;
  if (i === len - 1) {
    layer[key] = value;
  } else {
    if (force && typeof layer[key] === 'undefined') {
      layer[key] = pathBits[i+1] === '.' ? {} : [];
    }
    layer = layer[key];
  }
}
return obj;
$$ LANGUAGE plv8 IMMUTABLE;
force
参数具有两个功能—(1)用于设置
null
值。如果您基于其他不存在的列动态生成值,例如
blob->“不存在的值”
,则函数将输入null,您可能并不打算将该值设置为null。(2)目的是强制创建嵌套路径,如果它在您要修改的json对象中不存在。e、 g

json_replace(string('{"some_key": "some_val"}', 'other_key', 'new_val', true)
给予


您可以想象类似的函数来更新数字、删除键等。这基本上可以在postgres中的早期阶段启用类似mongo的功能,以实现快速原型化,并且随着模式的稳定,我们将内容分解为独立的列和表,以获得最佳性能

好奇地想知道…谁在编写教程来教用户创建这种疯狂的模式?这个问题是基于之前的一篇文章:可能是,但用这种方式更新json仍然值得怀疑,说得委婉一点。如果您需要更新json中存储的单个数据,那么这些数据几乎肯定是表中的实际字段。这种结构的效率在很大程度上取决于它的使用方式。例如,如果我当前的json字段被指定用于处理大量的“读取”请求,而不是以这种方式使用postgres json数据类型进行“写入”,那么就可以很好地实现这一目的。如果您所说的“读取”并不意味着“读取整个json数据,直到它从数据库中出来之前,都不知道里面有什么”,我想你会在接下来的路上遇到大惊喜。说到这里,从内部的角度来看,你可能会阅读应用程序中的整个字段,在其中进行编辑,然后更新整个字段……这就是Postgres在使用你的函数时所做的;唯一的区别是,您试图从PG内部松散地操纵json,这等于是重新发明了一个性能较差的
update
语句版本。。。。而不是,看我的答案。如果您发现自己在使用
eval
,请思考“哎呀,这样做的安全方法是什么”
eval()
几乎从来都不是正确的答案完美!谢谢lot@user3193043请接受答复。
json_replace(string('{"some_key": "some_val"}', 'other_key', 'new_val', true)
{"some_key": "some_val", "other_key": "new_val"}