嵌入的 json 对象上的唯一索引

Jas*_*Lee 4 postgresql indexing json unique-index postgresql-9.4

我现在正在测试 Postgresql 9.4 beta2。我想知道是否可以在嵌入式 json 对象上创建唯一索引?

我创建了一个表名products

CREATE TABLE products (oid serial primary key, data jsonb)
Run Code Online (Sandbox Code Playgroud)

现在,我尝试将 json 对象插入到数据列中。

{
    "id": "12345",
    "bags": [
        {
            "sku": "abc123",
            "price": 0,
        },
        {
            "sku": "abc123",
            "price": 0,
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

但是,我希望sku包包独一无二。这意味着 json 不能插入到 products 表中,因为sku在这种情况下它不是唯一的。

我试图创建一个像下面这样的唯一索引,但它失败了。

CREATE UNIQUE INDEX product_sku_index ON products( (data->'bags'->'sku') )
Run Code Online (Sandbox Code Playgroud)

有什么建议?

Erw*_*ter 5

UNIQUE INDEX由于多种原因,您在表达式上创建 a 的尝试注定会失败。

CREATE UNIQUE INDEX product_sku_index ON products( (data->'bags'->'sku') )

第一个也是最平凡的幸福是... 不参考任何东西。你可以引用数组的第一个元素
data->'bags'->'sku'

data->'bags'->0->>'sku'
Run Code Online (Sandbox Code Playgroud)

或更短:

data#>>'{bags,0,sku}'
Run Code Online (Sandbox Code Playgroud)

但该表达式只返回数组的第一个值。
您的定义:“我希望包的 sku 是独一无二的” .. 不清楚。您希望 的值sku是唯一的吗?在一个 JSON 对象中还是在列中的所有 json 对象中data?或者您想将数组限制为带有sku?

无论哪种方式,这些目标都不能通过简单的UNIQUE索引来实现。

可能的解决方案

如果您希望sku 在 中的所有 json 数组中都是唯一的data->'bags',有一种方法。取消嵌套数组并将所有单个sku值写入具有唯一(或 PK)约束的简单辅助表中的单独行:

CREATE TABLE prod_sku(sku text PRIMARY KEY);  -- PK enforces uniqueness
Run Code Online (Sandbox Code Playgroud)

此表可用于其他目的。
下面是一个与普通 Postgres 数组非常相似的问题的完整代码示例

仅适应取消嵌套技术。代替:

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;
Run Code Online (Sandbox Code Playgroud)

用:

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
Run Code Online (Sandbox Code Playgroud)

详情