4

我现在正在测试 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 不能插入到 products 表中,因为sku在这种情况下它不是唯一的。

我尝试创建如下所示的唯一索引,但失败了。

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

有什么建议么?

4

1 回答 1

5

由于多种原因,您在表达式上创建 a 的尝试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 数组非常相似的问题的完整代码示例:

仅调整取消嵌套技术。代替:

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

详细信息

于 2014-12-27T23:57:36.513 回答