我怎样才能实现mongo"放松"在postgres JSONB? (展平嵌套数组)

时间:2018-02-09 16:29:59

标签: mongodb postgresql jsonb

我最近考虑将我们的产品数据库从mongo迁移到postgres。来自mongoDb,我习惯于"放松"对象和数组。

假设您有以下对象:

{
  "styleGroupId": "2",
  "brand": "MOP",
  "colorVariants": [
    {
        "color": "red",
        "colorCode": "222",
        "sizeVariants": [
           {"gtin": "444",
           "size": "M"},
           {"gtin": "555",
           "size": "L"}
       ]
    },
    {
        "color": "blue",
        "colorCode": "111",
        "sizeVariants": [
           {"gtin": "66",
           "size": "M"},
           {"gtin": "77",
           "size": "L"}
       ]
    }
    ]
}

如果你想展平它,在mongo中使用以下内容:

db.test.aggregate([
{
    $unwind: "$colorVariants"
},
{
    $unwind: "$colorVariants.sizeVariants"
}
])

将产生如下对象:

{
    "_id" : ObjectId("5a7dc59dafc86d25964b873c"),
    "styleGroupId" : "2",
    "brand" : "MOP",
    "colorVariants" : {
        "color" : "red",
        "colorCode" : "222",
        "sizeVariants" : {
            "gtin" : "444",
            "size" : "M"
        }
    }
}

我花了几个小时寻找" mongo在postgres"但几乎找不到令人满意的答案。在postgres中查询JSONB数据的很多资源几乎都没有触及嵌套数组。希望这篇文章能帮助其他可怜的灵魂寻找从mongoDb到postgres的迁移。

2 个答案:

答案 0 :(得分:1)

功能:

create or replace function jsonb_unwind(target jsonb, path text[])
returns jsonb language plpgsql as $$
begin
    if jsonb_typeof(target #> path) = 'array' then
        return jsonb_set(target, path, target #> path -> 0);
    else
        return target;
    end if;
end $$;

使用示例:

select 
    jsonb_unwind(
        jsonb_unwind(json_data, '{colorVariants}'), 
        '{colorVariants, sizeVariants}')
from my_table;

Test it in rextester.

答案 1 :(得分:0)

在这篇文章中可以隐含地找到答案:How to query nested arrays in a postgres json column?

修改

与此回答配对use - to remove a key from a JSONB 从9.6

开始,有一种更简单的方法可以让你更接近mongo放松
  • 您需要在查询的FROM子句中声明每个数组级别
  • 从输出中排除每个嵌套对象,使其不会多次出现
  • 可选连接对象和子对象

将对象与共享键连接时,只保留||运算符右侧对象的键

-

SELECT
    data::jsonb - 'colorVariants' ||
    colorVariants.* - 'sizeVariants' || 
    sizeVariants.*
FROM
    test,
    jsonb_array_elements(data -> 'colorVariants') colorVariants,
    jsonb_array_elements(colorVariants -> 'sizeVariants') sizeVariants;

结果就是

                                                   ?column?
-------------------------------------------------------------------------------------------------------
 {"gtin": "11", "size": "M", "brand": "MOP", "color": "red", "colorCode": "222", "styleGroupId": "1"}
 {"gtin": "22", "size": "L", "brand": "MOP", "color": "red", "colorCode": "222", "styleGroupId": "1"}
 {"gtin": "33", "size": "M", "brand": "MOP", "color": "blue", "colorCode": "111", "styleGroupId": "1"}
 {"gtin": "44", "size": "L", "brand": "MOP", "color": "blue", "colorCode": "111", "styleGroupId": "1"}
 {"gtin": "444", "size": "M", "brand": "MOP", "color": "red", "colorCode": "222", "styleGroupId": "2"}
 {"gtin": "555", "size": "L", "brand": "MOP", "color": "red", "colorCode": "222", "styleGroupId": "2"}
 {"gtin": "66", "size": "M", "brand": "MOP", "color": "blue", "colorCode": "111", "styleGroupId": "2"}
 {"gtin": "77", "size": "L", "brand": "MOP", "color": "blue", "colorCode": "111", "styleGroupId": "2"}

旧帖子

  • 您必须在查询的FROM子句中声明每个数组级别
  • 您必须专门列出每个级别的属性。如果你只说明例如colorVariants嵌套数组也将被返回

因此,在特定情况下,解决方案将是:

SELECT 
    data->'brand' as brand, 
    data->'styleGroupId' as styleGroupId,
    colorVariants->'color' as color,
    colorVariants->'colorCode' as colorCode,
    sizeVariants->'gtin' as GTIN,
    sizeVariants->'size' as size
FROM 
    test,
    jsonb_array_elements(data->'colorVariants') colorVariants,
    jsonb_array_elements(colorVariants->'sizeVariants') sizeVariants

将导致

 brand | stylegroupid | color  | colorcode | gtin  | size
-------+--------------+--------+-----------+-------+------
 "MOP" | "1"          | "red"  | "222"     | "11"  | "M"
 "MOP" | "1"          | "red"  | "222"     | "22"  | "L"
 "MOP" | "1"          | "blue" | "111"     | "33"  | "M"
 "MOP" | "1"          | "blue" | "111"     | "44"  | "L"
 "MOP" | "2"          | "red"  | "222"     | "444" | "M"
 "MOP" | "2"          | "red"  | "222"     | "555" | "L"
 "MOP" | "2"          | "blue" | "111"     | "66"  | "M"
 "MOP" | "2"          | "blue" | "111"     | "77"  | "L"