查询复杂的 JSON 文档
在表中获取复杂的 JSON 文档:
CREATE TABLE mytable (data JSONB NOT NULL);
CREATE INDEX mytable_idx ON mytable USING gin (data jsonb_path_ops);
INSERT INTO mytable VALUES($$
{
    "name": "Alice",
    "emails": [
        "alice1@test.com",
        "alice2@test.com"
    ],
    "events": [
        {
            "type": "birthday",
            "date": "1970-01-01"
        },
        {
            "type": "anniversary",
            "date": "2001-05-05"
        }
    ],
    "locations": {
        "home": {
            "city": "London",
            "country": "United Kingdom"
        },
        "work": {
            "city": "Edinburgh",
            "country": "United Kingdom"
        }
    }
}
$$);
查询顶级元素:
SELECT data->>'name' FROM mytable WHERE data @> '{"name":"Alice"}';
查询数组中的简单项:
SELECT data->>'name' FROM mytable WHERE data @> '{"emails":["alice1@test.com"]}';
查询数组中的对象:
SELECT data->>'name' FROM mytable WHERE data @> '{"events":[{"type":"anniversary"}]}';
查询嵌套对象:
SELECT data->>'name' FROM mytable WHERE data @> '{"locations":{"home":{"city":"London"}}}';
@> 的性能与 -> 和 ->> 相比
重要的是要理解在查询的 WHERE 部分中使用 @>,-> 和 ->> 之间的性能差异。虽然这两个查询似乎大致相同:
SELECT data FROM mytable WHERE data @> '{"name":"Alice"}';
SELECT data FROM mytable WHERE data->'name' = '"Alice"';
SELECT data FROM mytable WHERE data->>'name' = 'Alice';
第一个语句将使用上面创建的索引,而后两个不会,需要完整的表扫描。
在获取结果数据时仍然允许使用 -> 运算符,因此以下查询也将使用索引:
SELECT data->'locations'->'work' FROM mytable WHERE data @> '{"name":"Alice"}';
SELECT data->'locations'->'work'->>'city' FROM mytable WHERE data @> '{"name":"Alice"}';