Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.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
Sql 如何根据Postgres中的筛选条件更新深度嵌套的JSON对象?_Sql_Json_Postgresql_Postgresql 9.5 - Fatal编程技术网

Sql 如何根据Postgres中的筛选条件更新深度嵌套的JSON对象?

Sql 如何根据Postgres中的筛选条件更新深度嵌套的JSON对象?,sql,json,postgresql,postgresql-9.5,Sql,Json,Postgresql,Postgresql 9.5,我有一个表mapping\u transform,其中有一个JSONB列content\u json包含如下内容 { "meta": {...}, "mapping": [ ..., { "src": "up", "dest": "down", ... }, ... ] } WITH elems AS (SELECT json_arra

我有一个表
mapping\u transform
,其中有一个JSONB列
content\u json
包含如下内容

{
    "meta": {...},
    "mapping": [
        ...,
        {
            "src": "up",
            "dest": "down",
            ...
        },
        ...
    ]
}
WITH elems AS (SELECT json_array_elements(content_json->'mapping') from mapping_transform),
     results SELECT * FROM elems WHERE json_array_elements->>'src' = 'up' and json_array_elements->>'dest' = 'down'
UPDATE mapping_transform
SET content_json = jsonb_set(results, '{"rule_names"}', '["some name"]'); -- this does obviously not work
我想在JSON对象中添加一个新的JSON条目(
“rule_names”):[“some name”]
)来匹配
src
=
up
dest
=
down
,这将导致

{
    "meta": {...},
    "mapping": [
        ...,
        {
            "src": "up",
            "dest": "down",
            ...,
            "rule_names": [ "some name" ]
        },
        ...
    ]
}
以下查询返回满足筛选要求的JSON对象:

WITH elems AS (SELECT json_array_elements(content_json->'mapping') from mapping_transform)
SELECT * FROM elems WHERE json_array_elements->>'src' = 'up' and json_array_elements->>'dest' = 'down';

-- Alternative

SELECT mt_entry
FROM mapping_transform,
LATERAL jsonb_array_elements(content_json::jsonb->'mapping') mt_entry
WHERE mt_entry->>'src' = 'up' and mt_entry->>'dest' = 'down';
我现在的问题是,我不知道如何将新条目添加到特定对象。我试过类似的东西

{
    "meta": {...},
    "mapping": [
        ...,
        {
            "src": "up",
            "dest": "down",
            ...
        },
        ...
    ]
}
WITH elems AS (SELECT json_array_elements(content_json->'mapping') from mapping_transform),
     results SELECT * FROM elems WHERE json_array_elements->>'src' = 'up' and json_array_elements->>'dest' = 'down'
UPDATE mapping_transform
SET content_json = jsonb_set(results, '{"rule_names"}', '["some name"]'); -- this does obviously not work
但这不会执行,因为
结果
是未知列。在分配给
content\u json
之前,我确实需要将
jsonb\u集的结果与
content\u json
的其余部分合并,因为否则它将覆盖整个内容

如何根据筛选条件更新特定的深度嵌套JSON对象?
如果我有一个定义良好的路径来确定我要更新的对象的位置,事情就会容易得多。但是,由于目标对象位于JSON数组中并且具有任意位置,查找和更新它要困难得多。请注意,我加入text=text(因为我不知道你的主键是什么-不推荐)。左侧为要更新的值,右侧为原始值:

vao=# with num as (select content_json,val,ord from mapping_transform, json_array_elements(content_json->'mapping') with ordinality as o (val,ord) where val->>'src' = 'up')
select
  jsonb_pretty(
    jsonb_set(t.content_json::jsonb,concat('{mapping,',(ord::int-1),'}')::text[],((t.content_json->'mapping'->(ord::int-1))::jsonb||'{"rule_names":["some name"]}')::jsonb)
  )
, jsonb_pretty(t.content_json::jsonb)
from mapping_transform t
join num on num.content_json::text = t.content_json::text
/* of course join should be on PK, not text representation*/
;
        jsonb_pretty         |        jsonb_pretty
-----------------------------+----------------------------
 {                          +| {                         +
     "meta": {              +|     "meta": {             +
         "a": true          +|         "a": true         +
     },                     +|     },                    +
     "mapping": [           +|     "mapping": [          +
         "a",               +|         "a",              +
         "c",               +|         "c",              +
         {                  +|         {                 +
             "a": 0,        +|             "a": 0,       +
             "src": "up",   +|             "src": "up",  +
             "dest": "down",+|             "dest": "down"+
             "rule_names": [+|         },                +
                 "some name"+|         "b"               +
             ]              +|     ]                     +
         },                 +| }
         "b"                +|
     ]                      +|
 }                           |
 {                          +| {                         +
     "meta": {              +|     "meta": {             +
         "a": true          +|         "a": true         +
     },                     +|     },                    +
     "mapping": [           +|     "mapping": [          +
         "a",               +|         "a",              +
         {                  +|         {                 +
             "a": 0,        +|             "a": 0,       +
             "src": "up",   +|             "src": "up",  +
             "dest": "down",+|             "dest": "down"+
             "rule_names": [+|         },                +
                 "some name"+|         "b"               +
             ]              +|     ]                     +
         },                 +| }
         "b"                +|
     ]                      +|
 }                           |
(2 rows)
建造:

vao=# create table mapping_transform(content_json jsonb);
CREATE TABLE
vao=#  insert into mapping_transform select '{
 "meta": {
  "a": true
 },
 "mapping": ["a",{
   "src": "up",
   "dest": "down",
   "a": 0
  },
  "b"
 ]
}';
INSERT 0 1
vao=#  insert into mapping_transform select '{
 "meta": {
  "a": true
 },
 "mapping": ["a","c",{
   "src": "up",
   "dest": "down",
   "a": 0
  },
  "b"
 ]
}';
INSERT 0 1

如果您熟悉JavaScript,您将乐于安装并使用此扩展,它允许您以本机方式修改json值,例如:

create extension if not exists plv8;

create or replace function update_mapping_v8(data json)
returns json language plv8 as $$
    var len = data['mapping'].length;
    for (var i = 0; i < len; i++) {
        var o = data['mapping'][i];
        if (o.src == 'up' && o.dest == 'down') {
            o.rule_names = 'some name'
        }
    }
    return data;
$$;

update mapping_transform
set content_json = update_mapping_v8(content_json);

问题是,假设目标对象位于数组中的位置0(
content\u json->“mapping”->0
),但对象可以位于任何位置,请参见我问题的最后一句。这就是为什么我需要某种过滤,不能“通过路径到达对象”。啊。有时间我去看看later@TorstenScholz动态更新了生成路径的答案