如何查询铁轨中的嵌套JSONB Postgres

发布于 2025-01-31 13:48:24 字数 613 浏览 3 评论 0 原文

我有一个称为 order>的表,带有 jsonb 列类型,称为 line_items line_items 列可以包含类似的嵌套值:

[
  {
    "id":9994857545813,
    "sku":"CLIPPING-PATH_C2_24H",
  },
  {
    "id":9994857578581,
    "sku":"NATURAL-SHADOW_C1_24H",
  }
]

上面的示例中有两个订单项,但它可以从1到任何数量的行项目不等。

我需要查询所有仅包含1个订单项的订单,其中sku =特定值,例如剪切path_c2_24h 按照上述示例。

因此,查询不应匹配上述示例,但以下示例只有1个订单项,而SKU =剪切path_c2_24h

[
  {
    "id":9994857545813,
    "sku":"CLIPPING-PATH_C2_24H",
  }
]

可以使用Rails Active Record编写查询吗?

I've a table called Order with a jsonb column type called line_items. The line_items column can contain nested values like this:

[
  {
    "id":9994857545813,
    "sku":"CLIPPING-PATH_C2_24H",
  },
  {
    "id":9994857578581,
    "sku":"NATURAL-SHADOW_C1_24H",
  }
]

The above example has two line items in it but it can vary from 1 to any number of line items.

I need to query all orders that contains only 1 line item where sku = a particular value such as CLIPPING-PATH_C2_24H as per above example.

So, the query should not match the above example but the following that has only 1 line item and sku=CLIPPING-PATH_C2_24H

[
  {
    "id":9994857545813,
    "sku":"CLIPPING-PATH_C2_24H",
  }
]

Can any help to write the query using Rails active record?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

高冷爸爸 2025-02-07 13:48:24

我能够使用jsonb_array_length方法来弄清楚这一点:

Order
.where("line_items @> ?", [{sku: sku}].to_json)
.where("jsonb_array_length(line_items) = 1")
.count
end

以下资源非常有帮助:
https://gist.github.com/mankind/1802dbb64fc24be33d434d593afd6221

I was able to figure this out using the jsonb_array_length method:

Order
.where("line_items @> ?", [{sku: sku}].to_json)
.where("jsonb_array_length(line_items) = 1")
.count
end

The following resource was extremely helpful:
https://gist.github.com/mankind/1802dbb64fc24be33d434d593afd6221

浅听莫相离 2025-02-07 13:48:24


SQL查询:选择JSONB_PATH_QUERY(order_json,'$ [*]?(@.sku ==“ clipping path_c2_24h'')从订单中;


都不容易为了使它正确,因为PL/PGSQL功能字符串的某些部分甚至包含4个单语引号。更好地使用加薪通知来逐步测试它。

CREATE OR REPLACE FUNCTION get_sku_CLIPPING_path (_sku text)
    RETURNS json
    AS $
DECLARE
    _sql text;
    _returnjson jsonb;
BEGIN
    RAISE NOTICE '%: _sku', $1;
    RAISE NOTICE '%', '$[*] ? (@.sku == ' || $1 || ')';
    RAISE NOTICE '%', $s$
    SELECT
        jsonb_path_query(order_json, $s$ || '''' || '$[*] ? (@.sku == ' || $1 || ')''' || ' from orders';
    _sql := $s$
    SELECT
        jsonb_path_query(order_json, $s$ || '''' || '$[*] ? (@.sku == ' || $1 || ')''' || ' )from orders';
    EXECUTE _sql
    USING _sku INTO _returnjson;
    RETURN (_returnjson::json);
END
$
LANGUAGE plpgsql;

调用:选择 *从get_sku_clipping_path('“剪辑path_c2_24h”');

demo
You can call plpghsql in ruby.(How to call plpgsql functions from Ruby on rails?)


sql query: select jsonb_path_query(order_json,'$[*] ? (@.sku == "CLIPPING-PATH_C2_24H")') from orders ;


it's not easy to get it right, since some part of PL/pgsql function string even include 4 single quotes. Better use raise notice to test it step by step.

CREATE OR REPLACE FUNCTION get_sku_CLIPPING_path (_sku text)
    RETURNS json
    AS $
DECLARE
    _sql text;
    _returnjson jsonb;
BEGIN
    RAISE NOTICE '%: _sku', $1;
    RAISE NOTICE '%', '$[*] ? (@.sku == ' || $1 || ')';
    RAISE NOTICE '%', $s$
    SELECT
        jsonb_path_query(order_json, $s$ || '''' || '$[*] ? (@.sku == ' || $1 || ')''' || ' from orders';
    _sql := $s$
    SELECT
        jsonb_path_query(order_json, $s$ || '''' || '$[*] ? (@.sku == ' || $1 || ')''' || ' )from orders';
    EXECUTE _sql
    USING _sku INTO _returnjson;
    RETURN (_returnjson::json);
END
$
LANGUAGE plpgsql;

call it: select * from get_sku_CLIPPING_path('"CLIPPING-PATH_C2_24H"');

久光 2025-02-07 13:48:24

首先,您没有嵌套的JSON。您只有一个带有对象的JSON数组。而且,您的JSON对象可以表示为表格。最好将这些对象存储在另一个表中,然后将一个对象设置为一个关系。
您可以有一个“订单”表和“ order_details”表。

要获取您需要的数据,首先我们需要查找具有“ sku”的记录:“剪切path_c2_24h” 然后我们需要解析JSON并从line_items字段中获取该对象。

SELECT
    t.*
  FROM orders o,
  -- extract object from array of json objects 
  LATERAL jsonb_path_query(o.line_items, '$[*] ? (@.sku == $value)', '{"value" : "CLIPPING-PATH_C2_24H"}') order_line,
  -- convert "sku":"NATURAL-SHADOW_C1_24H" into columns 
  LATERAL jsonb_to_record(order_line) as t(id bigint, sku text)
  WHERE
    -- find record which has "sku":"NATURAL-SHADOW_C1_24H"
    o.line_items @> '[{"sku":"NATURAL-SHADOW_C1_24H"}]';

结果就是这样;

           id | sku                 
------------- | --------------------
9994857545813 | CLIPPING-PATH_C2_24H

小提琴是

First things first, you don't have a nested json. You just have a json array with objects. Moreover your json objects can be representable as tabular. It's better to store those objects in another table and setup a one to many relationship.
You can have an "orders" table and an "order_details" table.

To get data you need, first we need to find records which have "sku":"CLIPPING-PATH_C2_24H" then we need to parse json and get that object from line_items fields.

SELECT
    t.*
  FROM orders o,
  -- extract object from array of json objects 
  LATERAL jsonb_path_query(o.line_items, '$[*] ? (@.sku == $value)', '{"value" : "CLIPPING-PATH_C2_24H"}') order_line,
  -- convert "sku":"NATURAL-SHADOW_C1_24H" into columns 
  LATERAL jsonb_to_record(order_line) as t(id bigint, sku text)
  WHERE
    -- find record which has "sku":"NATURAL-SHADOW_C1_24H"
    o.line_items @> '[{"sku":"NATURAL-SHADOW_C1_24H"}]';

Result will be like this;

           id | sku                 
------------- | --------------------
9994857545813 | CLIPPING-PATH_C2_24H

fiddle is here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文