简体   繁体   English

如何从 JSONB 类型数组中按值删除 object?

[英]How to remove object by value from a JSONB type array?

I want to remove a JSONB object by their unique 'id' value from a JSONB array.我想通过 JSONB 数组中唯一的“id”值删除 JSONB object。 I am no expert at writing SQL code, but I managed to write the concatenate function.我不是编写 SQL 代码的专家,但我设法编写了连接 function。

For an example: Remove this object from an array below.例如:从下面的数组中删除这个 object。

  {
      "id": "ad26e2be-19fd-4862-8f84-f2f9c87b582e",
      "title": "Wikipedia",
      "links": [
          "https://en.wikipedia.org/1",
          "https://en.wikipedia.org/2"
      ]
    },

Schema :架构

CREATE TABLE users (
    url text not null,
    user_id SERIAL PRIMARY KEY,
    name VARCHAR,
    list_of_links jsonb default '[]'
);

list_of_links format: list_of_links格式:

[
  {
      "id": "ad26e2be-19fd-4862-8f84-f2f9c87b582e",
      "title": "Wikipedia",
      "links": [
          "https://en.wikipedia.org/1",
          "https://en.wikipedia.org/2"
      ]
    },
      {
      "id": "451ac172-b93e-4158-8e53-8e9031cfbe72",
      "title": "Russian Wikipedia",
      "links": [
          "https://ru.wikipedia.org/wiki/",
          "https://ru.wikipedia.org/wiki/"
      ]
    },
      {
      "id": "818b99c8-479b-4846-ac15-4b2832ec63b5",
      "title": "German Wikipedia",
      "links": [
          "https://de.wikipedia.org/any",
          "https://de.wikipedia.org/any"
      ]
    },
    ...
]

The concatenate function:串联 function:

update users set list_of_links=(
     list_of_links || (select *
         from jsonb_array_elements(list_of_links) 
         where value->>'id'='ad26e2be-19fd-4862-8f84-f2f9c87b582e'
          )
  )
where url='test'
returning *
;

Your json data is structured so you have to unpack it, operate on the unpacked data, and then repack it again:您的json数据是结构化的,因此您必须对其进行解压缩,对解压缩的数据进行操作,然后再次重新打包:

SELECT u.url, u.user_id, u.name, 
       jsonb_agg(
           jsonb_build_object('id', l.id, 'title', l.title, 'links', l.links)
       ) as list_of_links
FROM users u
CROSS JOIN LATERAL jsonb_to_recordset(u.list_of_links) AS l(id uuid, title text, links jsonb)
WHERE l.id != 'ad26e2be-19fd-4862-8f84-f2f9c87b582e'::uuid
GROUP BY 1, 2, 3

The function jsonb_to_recordset is a set-returning function so you have to use it as a row source, joined to its originating table with the LATERAL clause so that the list_of_links column is available to the function to be unpacked. function jsonb_to_recordset是一个集合返回 function,因此您必须将其用作行源,使用LATERAL子句连接到其原始表,以便list_of_links列可用于要解包的 function。 Then you can delete the records you are not interested in using the WHERE clause, and finally repack the structure by building the record fields into a jsonb structure and then aggregating the individual records back into an array.然后您可以使用WHERE子句删除您不感兴趣的记录,最后通过将记录字段构建为jsonb结构然后将各个记录聚合回数组来重新打包结构。

I wrote this on JS but that does not matter to how it works.我是在 JS 上写的,但这对它的工作方式无关紧要。 Essentially, its getting all the items from the array, then finding the matching id which returns an index.本质上,它从数组中获取所有项目,然后找到返回索引的匹配 id。 And using that index, I use "-" operator which takes the index and removes it from the array.并使用该索引,我使用“-”运算符获取索引并将其从数组中删除。 Sorry if my grammar is bad.对不起,如果我的语法不好。

    //req.body is this JSON object
    //{"url":"test", "id": "ad26e2be-19fd-4862-8f84-f2f9c87b582e"}
    var { url, id } = req.body;
    pgPool.query(
        `
                select list_of_links
                from users
                where url=$1;
        `,
        [url],
        (error, result) => {
            //block code executing further if error is true
            if (error) {
                res.json({ status: "failed" });
                return;
            }
            if (result) {
                // this function just returns the index of the array element where the id matches from request's id
                // 0, 1, 2, 3, 4, 5
                var index_of_the_item = result.rows.list_of_links
                    .map(({ id: db_id }, index) =>
                        db_id === id ? index : false
                    )
                    .filter((x) => x !== false)[0];
                //remove the array element by it's index
                pgPool.query(
                    `
                    update users
                    set list_of_links=(
                       list_of_links - $1::int
                    )
                    where url=$2
                    ;
                   `,
                    [index_of_the_item, url], (e, r) => {...}

                );
            }
        }
    );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM