我们说[在Postgres 9.6 ]中有一个名为xyz
的JSONB列。在更新中,我想将此列的.foo.bar
键设置为{"done":true}
。
但是更新必须容忍xyz
的更新前价值是从{}
到
{
"abc": "Hello"
}
或者
{
"foo": {
"baz": { "done": false }
},
"abc": "Hello"
}
所以我不能马上使用jsonb_set
,因为如果xyz->foo
未定义则失败。在这种情况下,我可以使用jsonb_insert
,但如果已经定义xyz->foo
,则会失败。
所以我尝试使用连接,例如
jsonb_set(
jsonb_set(xyz, '{foo}', '{}'::jsonb || xyz->'foo', true),
'{foo, bar}', '{"done":true}', true
)
...在foo
未定义时也会失败,因为xyz->'foo'
为null
会覆盖连接中的{}
。
显然我可以编写一个使用if
来解决这个问题的函数,但我真的觉得我应该能够在一次更新中完成它。
答案 0 :(得分:8)
对于这个例子:
{
"foo": {
"baz": { "done": false }
},
"abc": "Hello"
}
插入强>
您必须使用jsonb_insert
,您可以使用SELECT
进行测试。
SELECT jsonb_insert(xyz, '{foo,bar}', '{"done":true}'::jsonb) FROM tablename;
注意:使用jsonb_insert
对于正确设置路径非常重要。这里的路径是'{foo:bar}',这意味着您将在名为foo
的对象bar
中插入JSON。
因此,结果是:
{
"abc": "Hello",
"foo": {
"baz": {
"done": false
},
"bar": {
"done": true
}
}
}
设置:强>
要修改bar
并将其设置为false,您必须使用jsonb_set
。您可以使用SELECT
:
SELECT jsonb_set(xyz, '{foo,bar}', '{"done":false}'::jsonb) FROM tablename;
返回:
{
"abc": "Hello",
"foo": {
"baz": {
"done": false
},
"bar": {
"done": false
}
}
}
更新设置和插入
当对象存在时使用jsonb_set
,而当对象存在时使用jsonb_insert
。要在不知道使用哪一个的情况下进行更新,您可以使用CASE
UPDATE tablename SET
xyz= (CASE
WHEN xyz->'foo' IS NOT NULL
THEN jsonb_set(xyz, '{foo,bar}', '{"done":false}'::jsonb)
WHEN xyz->'foo' IS NULL
THEN jsonb_insert(xyz, '{foo}', '{"bar":{"done":true}}'::jsonb)
END)
WHERE id=1;-- if you use an id to identify the JSON.
您可以为更具体的值添加一些CASE子句。
答案 1 :(得分:0)
你可以使用||连接。它将覆盖或添加任何json值。
SELECT '{}'::jsonb || '{"foo":"bar"}'::jsonb
UPDATE tablename SET jdoc = jdoc || '{"foo":"bar"}'::jsonb
就这么简单。我很少使用我的软件中的功能。