Как удалить элемент jsonb во вложенном массиве psql - PullRequest
1 голос
/ 17 апреля 2020

У меня есть таблица пользователей:

`CREATE TABLE users(
    id SERIAL PRIMARY KEY NOT NULL,
    username TEXT UNIQUE,
    saved_articles JSONB[],
  )`

Я добавил пользователя примерно так:

      "INSERT INTO users (username, saved_articles) VALUES (?, array[]::jsonb[]) RETURNING id, username, saved_articles"

После добавления некоторых статей у меня есть эта форма данных:

{ id: 1,
  username: 'test',
  saved_articles:
   [ { url: 'test',
       title: '',
       author: '',
       source: '',
       content:"",
       urlToImage: '' 
     },
     { url: 'not-test',
       title: '',
       author: '',
       source: '',
       content:"",
       urlToImage: '' 
     }
   ]
}

Я хочу иметь возможность удалить указанный элемент c из массива save_articles на основе значения URL.

Например, если в качестве значения моего URL-адреса указано «test», после выполнения запроса мои данные должно выглядеть так:

{ id: 1,
  username: 'test',
  saved_articles:
   [ { url: 'not-test',
       title: '',
       author: '',
       source: '',
       content:"",
       urlToImage: '' 
     }
   ]
}

1 Ответ

0 голосов
/ 19 апреля 2020

Прежде всего, формат значения столбца JSONB должен быть фиксированным. Это можно проверить с помощью CAST ing AS JSONB с помощью оператора SELECT, например

SELECT '{ "id": "1",
  "username": "test",
  "saved_articles":
   [ { "url": "test",
       "title": "",
       "author": "",
       "source": "",
       "content":"",
       "urlToImage": "" 
     },
     { "url": "not-test",
       "title": "",
       "author": "",
       "source": "",
       "content":"",
       "urlToImage": "" 
     }
   ]}'::jsonb

, независимо от того, возвращает ошибку или нет.

Затем удалите нужный элемент из массива. с помощью функции jsonb_array_elements(json_data -> 'saved_articles') вместе с критериями ->> 'url' != 'test'.

А затем восстановите массив, оставшиеся элементы, используя jsonb_build_array и jsonb_object_agg.

На последнем шаге объедините часть, которая не содержит этот отдельный массив, извлеченный с помощью json_data #- '{saved_articles}':

SELECT js0||jsonb_object_agg( 'saved_articles', js1 ) AS "Result JSONB"
  FROM
  (
   SELECT json_data #- '{saved_articles}' AS js0, jsonb_build_array( js ) AS js1
     FROM tab
    CROSS JOIN jsonb_array_elements(json_data -> 'saved_articles') js
    WHERE js ->> 'url' != 'test'
   ) q
 GROUP BY js0

Demo

...