如何在Postgresql中选择和更新JSON数组元素?

时间:2017-06-01 02:10:35

标签: sql json postgresql

我正在使用9.6版。我的文档看起来像这样:

{
    "name" : "John Doe", 
    "phones" : [
        {
            "type" : "mobile", 
            "number" : "555-555-0000",
            "deleted": false
        }, 
        {
            "type" : "home", 
            "number" : "555-555-0001",
            "needsUpdated" : true
        }, 
        {
            "type" : "work", 
            "number" : "555-555-0002"
        }
    ]
}

我是这样创建的:

create table t_json (c_json json not null);

insert into t_json (c_json) values ('{"name":"John Doe","phones": [{"type":"mobile","number":"555-555-0000"},{"type":"home","number":"555-555-0001"},{"type": "work","number": "555-555-0002"}]}');

insert into t_json (c_json) values ('{"name":"Jane Dane","phones": [{"type":"mobile","number":"555-555-0030"},{"type":"home","number":"555-555-0020"},{"type": "work","number": "555-555-0010"}]}');

现在我想弄明白如何A,选择名称为 John Doe 的行,并将其手机号码更新为“555-555-0003”。< / p>

从这里Postgresql 9.6 documentation我发现我可以查询这样的正确文档:

select c_json from t_json where c_json->>'name' = 'John Doe';

但是我没有看到如何按类型选择手机阵列中的正确子文档,并更新数值。任何人都可以帮助我吗?

修改

我需要假设子文档有额外的值并且不一致。所以我在上面添加了一些。我很确定此时无法在没有数据丢失的情况下进行此更新。

1 个答案:

答案 0 :(得分:10)

  

如何按类型选择手机阵列中的正确子文档?

如果您想获取电话号码,请使用此号码。相应的文件是https://www.postgresql.org/docs/9.6/static/queries-table-expressions.html#QUERIES-LATERAL

SELECT c_json ->> 'name', phones.type, phones.number
    FROM t_json
    CROSS JOIN json_to_recordset(c_json -> 'phones')
        AS phones("type" TEXT, "number" TEXT);

如果您想通过电话号码进行搜索,则可以:

SELECT * FROM t_json
    WHERE (c_json -> 'phones')::JSONB @>
        '[{"type":"mobile","number":"555-555-0000"}]'::JSONB;
  

如何更新数字值?

正如评论中所提到的,有一个类似的问题,How do I modify fields inside the new PostgreSQL JSON datatype?

还有其他方法可以做到这一点,比如

UPDATE t_json SET c_json = newvalue FROM (
    SELECT to_json(updated) AS newvalue FROM (
        SELECT c_json ->> 'name' as "name",
            json_agg(json_build_object('type', phones.type, 'number',
                CASE phones.type WHEN 'mobile' THEN '555-555-0003' ELSE phones.number END)
            ) AS phones
    FROM t_json
    CROSS JOIN json_to_recordset(c_json -> 'phones')
        AS phones("type" TEXT, "number" TEXT)
    WHERE c_json->>'name' = 'John Doe'
    GROUP BY name
    ) as updated
) AS sub WHERE c_json ->> 'name' = 'John Doe';