Уникальный индекс для встроенного объекта json
Я сейчас тестирую Postgresql 9.4 beta2. Мне интересно, возможно ли создать уникальный индекс для встроенного объекта json?
Я создаю имя таблицы products
:
CREATE TABLE products (oid serial primary key, data jsonb)
Теперь я пытаюсь вставить объект JSON в столбец данных.
{
"id": "12345",
"bags": [
{
"sku": "abc123",
"price": 0,
},
{
"sku": "abc123",
"price": 0,
}
]
}
Тем не менее, я хочу sku
сумок, чтобы быть уникальным. Это означает, что JSON не может быть вставлен в таблицы продуктов, потому что sku
не уникален в этом случае.
Я пытался создать уникальный индекс, как показано ниже, но это не удалось.
CREATE UNIQUE INDEX product_sku_index ON products( (data->'bags'->'sku') )
Какие-либо предложения?
1 ответ
Ваша попытка создать UNIQUE INDEX
на выражение должно было произойти сбой по нескольким причинам.
CREATE UNIQUE INDEX product_sku_index ON products( (data->'bags'->'sku') )
Первое и самое тривиальное, что... data->'bags'->'sku'
ничего не ссылается. Вы можете ссылаться на первый элемент массива с помощью
data->'bags'->0->>'sku'
или короче:
data#>>'{bags,0,sku}'
Но это выражение возвращает только первое значение массива.
Ваше определение: "Я хочу, чтобы sku сумок было уникальным".. неясно. Вы хотите ценность sku
быть уникальным? Внутри одного объекта JSON или среди всех объектов JSON в столбце data
? Или вы хотите ограничить массив одним элементом с sku
?
В любом случае, ни одна из этих целей не может быть реализована с помощью простого UNIQUE
индекс.
Возможное решение
Если ты хочешь sku
значения должны быть уникальными для всех массивов JSON в data->'bags'
, есть выход. Разверните массив и напишите все индивидуально sku
значения для разделения строк в простой вспомогательной таблице с уникальным (или PK) ограничением:
CREATE TABLE prod_sku(sku text PRIMARY KEY); -- PK enforces uniqueness
Эта таблица может быть полезна для дополнительных целей.
Вот полный пример кода для очень похожей проблемы с простыми массивами Postgres:
Адаптируйте только метод unnesting. Вместо:
DELETE FROM hostname h
USING unnest(OLD.hostnames) d(x)
WHERE h.hostname = d.x;
...
INSERT INTO hostname(hostname)
SELECT h
FROM unnest(NEW.hostnames) h;
Использование:
DELETE FROM prod_sku p
USING jsonb_array_elements(NEW.data->'bags') d(x)
WHERE p.sku = d.x->>'sku';
...
INSERT INTO prod_sku(sku)
SELECT b->>'sku'
FROM jsonb_array_elements(NEW.data->'bags') b
Детали для этого: