当前位置: 首页 > 面试题库 >

如何基于Postgres中的过滤条件更新深层嵌套的JSON对象?

张瀚漠
2023-03-14
问题内容

我有一个mapping_transform带有JSONB列的表,content_json其中包含类似

{
    "meta": {...},
    "mapping": [
        ...,
        {
            "src": "up",
            "dest": "down",
            ...
        },
        ...
    ]
}

我想向"rule_names": [ "some name" ]匹配src=updest=的JSON对象添加一个新的JSON条目()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';

我现在的问题是,我不知道如何将新条目添加到特定对象。我尝试了类似的东西

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

但这不会像results未知列那样执行。在分配给之前,我还确实需要将的结果jsonb_set与其余的合并,因为否则会覆盖整个内容。content_json``content_json

如何根据过滤条件更新特定的深层嵌套JSON对象?如果我有一个明确的路径来确定要更新的对象,那么事情会容易得多。但是由于目标对象位于JSON数组内并且具有
任意位置 ,因此查找和更新目标要困难得多。


问题答案:

如果您熟悉JavaScript,将很乐意安装和使用JavaScript过程语言plv8。此扩展允许您本地修改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);

对于MS
Windows用户:准备安装Windows二进制文件。

一个plpgsql替代解决方案使用jsonb类型:

create or replace function update_mapping_plpgsql(data jsonb)
returns json language plpgsql as $$
declare
    r record;
begin
    for r in
        select value, ordinality- 1 as pos
        from jsonb_array_elements(data->'mapping') with ordinality
        where value->>'src' = 'up' and value->>'dest' = 'down'
    loop
        data = jsonb_set(
            data,
            array['mapping', r.pos::text],
            r.value || '{"rule_names": "some name"}'
            );
    end loop;
    return data;
end $$;

update mapping_transform
set content_json = update_mapping_plpgsql(content_json::jsonb);


 类似资料:
  • 我有多个嵌套文档doc。嵌套查询工作正常,但它们仍然会返回所有嵌套对象(即整个文档),即使搜索查询只匹配少数嵌套对象。但是,它确实将文档作为一个整体进行过滤。 下面是一个例子: 当在地址中搜索时,理想情况下,我应该只获得带有一个嵌套对象的,但我会获得所有嵌套对象。如何筛选返回的嵌套对象? 示例查询: 该查询的输出是和所有员工,而我只想要。

  • 感谢您的回复 编辑: 我试图计数对象之间指定日期范围内的筛选器内的嵌套对象。在ElasticSearch上这样做可能吗?简单地说,我想查看,客户谁有1个订单或多个订单取决于输入在一个指定的日期。 我知道如何获得客户的每日计数,但如果我想计数在指定日期范围内有1个订单的客户在一组每日报表中怎么办? 我所期望的可能的回应:

  • 问题内容: 这是我的表(简体,仅重要的列): 以及一些样本数据: 我想选择键下任意位置的行。像这样的东西: 数据完全像样本中一样嵌套(仅一层)。 当前,我们正在使用PostgreSQL 9.3.5。 在PostgreSQL 9.3中可以吗?也许是9.4? 问题答案: 您的查询已关闭。 是关键功能。还是为了。进行了一些改进: 旧的sqlfiddle db <> fiddle在这里 已经返回该值作为数

  • 问题内容: 我正在尝试基于一些嵌套对象来过滤数组。 输入数组如下所示: 我希望这种情况的输出如下所示: 我正在使用此公式来做到这一点: 输出几乎是好的,但它返回的对象带有所有带有姓氏的对象(最好检查一下小提琴:D),而不是将其删除。我如何改善过滤? 问题答案: 调用之后,您需要将结果通过管道传递到,如下所示: 我在这里假设您不想操纵原始数组。因此,我正在使用Object.assign。

  • 基于 那个东西的 以下是我目前所尝试的: 我想使用一个Java8流和两个getter的lambdas来完成这一操作,这两个getter最终检索用于确定唯一性的属性,但不确定如何实现。当用于比较的属性位于pojo的顶层时,我知道如何做,但当属性嵌套在另一个对象中时,我不知道如何做。

  • 我有一个类似这样的组对象 和如下所示的Item对象