【问题标题】:How Do I Access Nested JSON in Postgresql 9.4?如何在 Postgresql 9.4 中访问嵌套 JSON?
【发布时间】:2025-12-20 20:40:11
【问题描述】:

我正在尝试访问 Postgresql 9.4 中的嵌套 jsonb 字段。但是我很难根据嵌套的 jsonb 值检索记录。有没有人在这方面取得成功?

  • 首先,我创建了表:

    CREATE TABLE Meal (
        id INT
      , recipe JSONB
    );
    
  • 其次,我在 dbo.Meal 中插入了以下记录: (我通过 jsonlint.com 运行了 json,它返回有效)

    INSERT INTO Meal (id, recipe)
    VALUES (
    1,
    '{
      "meal": [{
      "calories" : 900,
      "serves" : [{"min": 2, "max": 4}],
      "fruit" : [{"id": 1, "qty": 2}, {"id": 4, "qty": 3}],
      "veggie" : [{"id": 4, "qty": 1}, {"id": 2, "qty": 10}]
     }]
    }');
    
  • 第三,我尝试了以下查询以根据卡路里计数检索此记录(均无效):

这些返回 0 条记录:

SELECT * FROM Meal ...

WHERE recipe::json#>>'{meal, calories}' = '900';
WHERE recipe::json->>'{meal, calories}' = '900';
WHERE recipe::json->>'meal[calories]' = '900';
WHERE recipe::json->>'{meal[calories]}' = '900';
WHERE recipe::json#>>'{meal[calories]}' = '900';
WHERE recipe::json#>>'{meal.calories}' = '900';
WHERE recipe::json->>'{meal.calories}' = '900';

WHERE recipe::jsonb#>>'{meal, calories}' = '900';
WHERE recipe::jsonb->>'{meal, calories}' = '900';
WHERE recipe::jsonb#>>'{meal[calories]}' = '900';
WHERE recipe::jsonb->>'{meal[calories]}' = '900';
WHERE recipe::jsonb->>'meal[calories]' = '900';
WHERE recipe::jsonb#>'{meal, calories}' = '900';
WHERE recipe::jsonb->'{meal, calories}' = '900';
WHERE recipe::jsonb->'meal[calories]' = '900';
WHERE recipe::jsonb#>'{meal[calories]}' = '900';
WHERE recipe::jsonb->'{meal[calories]}' = '900';
WHERE recipe::jsonb#>>'{meal.calories}' = '900';
WHERE recipe::jsonb#>'{meal.calories}' = '900';
WHERE recipe::jsonb->>'{meal.calories}' = '900';
WHERE recipe::jsonb->'{meal.calories}' = '900';

这些会导致失败(语法错误):

SELECT * FROM Meal ...

WHERE recipe::json#>'{meal, calories}' = '900';
WHERE recipe::json->'{meal, calories}' = '900';
WHERE recipe::json#>>'meal[calories]' = '900';
WHERE recipe::json#>'meal[calories]' = '900';
WHERE recipe::json->'meal[calories]' = '900';
WHERE recipe::json#>'{meal[calories]}' = '900';
WHERE recipe::json->'{meal[calories]}' = '900';
WHERE recipe::json#>'{meal.calories}' = '900';
WHERE recipe::json->'{meal.calories}' = '900';

WHERE recipe::jsonb#>>'meal[calories]' = '900';
WHERE recipe::jsonb#>'meal[calories]' = '900';

如果您有任何建议,我将不胜感激。

【问题讨论】:

  • 我可能已经弄清楚了。根据 OP 中的表,以下 2 个查询正确返回了一条记录: (1) SELECT * FROM Meal WHERE recipe @> '{"meal":[{"calories":900}]}'::jsonb; (2) SELECT * FROM Meal WHERE recipe @> '{"meal":[{"calories":900}]}'::jsonb AND recipe @> '{"meal":[{"fruit":[{" id":4}]}]}'::jsonb;以下查询不会返回记录(这是正确的,因为meal.fruit.id = 40 不存在):(3)SELECT * FROM Meal WHERE recipe @> '{"meal":[{"calories":900 }]}'::jsonb AND recipe @> '{"meal":[{"fruit":[{"id":40}]}]}'::jsonb;希望这会有所帮助!
  • 问一个关于不到 72 小时的 beta 版本中的新功能的问题不会产生很多关于 SO 的知情答案,如果有的话。在这种情况下的问题最好在 postgresql 邮件列表中提出,-hackers 会浮现在脑海中。

标签: json postgresql


【解决方案1】:

选择餐点:

select * from meal where recipe #>> '{meal,0,calories}' = '900';

如果您想在数组meal 中找到这些条目,您必须迭代数组以检查每个键。没有通配符数组索引或对象名称占位符 - 你不能写 {meal,*,calories}。反正还没有; json 功能不断改进。

我会这样做:

select meal.id, recipe_entry 
from meal,
lateral jsonb_array_elements(recipe -> 'meal') recipe_entry 
where CAST(recipe_entry ->> 'calories' AS integer) = 900;

未来对 json 功能的一些可能的增强将使这更容易。可以返回一个集合的支持通配符的路径搜索功能将非常有用 - 可能作为对json_extract_path 的增强。如果有人证明很热心,也许在 9.5 中。真正有用的另一件事是转换函数或 json 标量的强制转换,因此我们可以编写 recipe_entry -> 'calories' = to_json(900) 并获得类似 Javascript 的相等比较语义,而不是依赖于上述强制转换。

【讨论】:

  • 我将其标记为答案,因为它有效并且...它还有助于我在比较中使用 jsonb 值(例如,将 craig 的查询从“= 900”调整为“> 900”不会返回一条记录。这是正确的...感谢您的帮助!我今天大部分时间都在尝试找出比较的东西。
  • 在 PostgreSQL 9.5 上,您可以使用 @> 运算符,如下所述:*.com/questions/28486192/…