MongoDB聚合与嵌套对象数组位于对象数组内。

huangapple go评论57阅读模式
英文:

mongodb aggergate with nested arrays of objects inside an array of objects

问题

以下是翻译好的代码部分:

我得到了以下的数据结构

    data = {
        "_id": "abc",
        "field": "value",
        "misc": {
            "height": 1.1,
        },
        "sales": [
            {
                "label": 1,
                "codes": [
                    {
                        "code": 123456,
                        "active": True
                    },
                    {
                        "code": 234567,
                        "active": False
                    },
                    {
                        "code": 345678,
                        "active": False
                    },
                ],
                "prices": [
                    {
                        "price": 2.99,
                        "valid_from": datetime(year=2023, month=3, day=1)
                    },
                    {
                        "price": 3.99,
                        "valid_from": datetime(year=2023, month=4, day=1)
                    },
                    {
                        "price": 4.99,
                        "valid_from": datetime(year=2023, month=5, day=1)
                    },
                    {
                        "price": 5.99,
                        "valid_from": datetime(year=2023, month=6, day=1)
                    },
                ]
            },
            {
                "label": 2,
                "codes": [
                    {
                        "code": 987654,
                        "active": True
                    },
                    {
                        "code": 876543,
                        "active": False
                    },
                    {
                        "code": 765432,
                        "active": False
                    },
                ],
                "prices": [
                    {
                        "price": 2.99,
                        "valid_from": datetime(year=2023, month=3, day=1)
                    },
                    {
                        "price": 3.99,
                        "valid_from": datetime(year=2023, month=4, day=1)
                    },
                    {
                        "price": 4.99,
                        "valid_from": datetime(year=2023, month=5, day=1)
                    },
                    {
                        "price": 6.99,
                        "valid_from": datetime(year=2023, month=6, day=1)
                    },
                }
            },
    
        ]
    }

我的目标是输出标签为1的对象对我来说这个筛选聚合操作可以工作

    db.MasterData.aggregate([
        
        { "$match": { "_id": "abc" } },
    
        {
            "$project": {
                "field": 1,
                "sales": {
                    "$filter": {
                        "input": "$sales",
                        "as": "item",
                        "cond": {
                            "$eq": ["$$item.label", 1]
                        }
                    }
                },
            }
        }
        
    ])

但我还想筛选嵌套数组codes和prices例如只显示active为True的code和大于今天的价格但我无法弄清楚如何访问嵌套数组这个查询导致空结果

    db.MasterData.aggregate([
        
        { "$match": { "_id": "abc" } },
    
        {
            "$project": {
                "field": 1,
                "sales.codes": {
                    "$filter": {
                        "input": "$sales.codes",
                        "as": "item",
                        "cond": {
                            "$eq": ["$$item.active", True]
                        }
                    }
                },
            }
        }
        
    ])

有人能帮我吗

此外我在思考这是否是处理这种数据结构的最佳方式是否将销售部分插入到另一个集合并引用主数据会更好据我所知根据我目前对MongoDB的了解应尽量避免使用引用文档除非必要
英文:

I got following data structure:

data = {
"_id": "abc",
"field": "value",
"misc": {
"height": 1.1,
},
"sales": [
{
"label": 1,
"codes": [
{
"code": 123456,
"active": True
},
{
"code": 234567,
"active": False
},
{
"code": 345678,
"active": False
},
],
"prices": [
{
"price": 2.99,
"valid_from": datetime(year=2023, month=3, day=1)
},
{
"price": 3.99,
"valid_from": datetime(year=2023, month=4, day=1)
},
{
"price": 4.99,
"valid_from": datetime(year=2023, month=5, day=1)
},
{
"price": 5.99,
"valid_from": datetime(year=2023, month=6, day=1)
},
]
},
{
"label": 2,
"codes": [
{
"code": 987654,
"active": True
},
{
"code": 876543,
"active": False
},
{
"code": 765432,
"active": False
},
],
"prices": [
{
"price": 2.99,
"valid_from": datetime(year=2023, month=3, day=1)
},
{
"price": 3.99,
"valid_from": datetime(year=2023, month=4, day=1)
},
{
"price": 4.99,
"valid_from": datetime(year=2023, month=5, day=1)
},
{
"price": 6.99,
"valid_from": datetime(year=2023, month=6, day=1)
},
]
},
]
}

My Goal is to output the label 1 object. This Filter Aggregate works for me:

db.MasterData.aggregate([
{ "$match": { "_id": "abc" } },
{
"$project": {
"field": 1,
"sales": {
"$filter": {
"input": "$sales",
"as": "item",
"cond": {
"$eq": ["$$item.label", 1]
}
}
},
}
}
])

But I want also to filter the nested arrays codes and prices, for example show only the code where active is True and only the prices which are greater than today. But I couldn’t figure out how to access the nested arrays. This query results in an empty outcome:

db.MasterData.aggregate([
{ "$match": { "_id": "abc" } },
{
"$project": {
"field": 1,
"sales.codes": {
"$filter": {
"input": "$sales.codes",
"as": "item",
"cond": {
"$eq": ["$$item.active", True]
}
}
},
}
}
])

Can someone help me with this please?

Also, I am wondering if this is the best way to deal with this Data structure. Would it be better to insert the sales Part in another collection with reference to the Main Data? As far as I know at this point of my MongoDB journey, using reference documents should be avoid when it could be.

答案1

得分: 1

以下是翻译好的内容:

也许是这样的:

db.collection.aggregate([
  {
    "$match": {
      "_id": "abc"
    }
  },
  {
    "$addFields": {
      "sales": {
        "$filter": {
          "input": "$sales",
          "as": "s",
          "cond": {
            "$eq": ["$$s.label", 1]
          }
        }
      }
    }
  },
  {
    "$addFields": {
      "sales": {
        "$map": {
          "input": "$sales",
          "as": "s",
          "in": {
            "$mergeObjects": [
              "$$s",
              {
                "codes": {
                  "$filter": {
                    "input": "$$s.codes",
                    "as": "c",
                    "cond": {
                      "$eq": ["$$c.active", true]
                    }
                  }
                },
                "prices": {
                  "$filter": {
                    "input": "$$s.prices",
                    "as": "p",
                    "cond": {
                      "$gt": ["$$p.valid_from", 1]
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
])

解释:

  1. 匹配具有"_id"等于"abc"的文档。
  2. 使用"$addFields"来筛选仅具有"label"等于1的销售对象。
  3. 使用"$addFields"将销售对象内的"codes"和"prices"字段分别筛选为仅包含活动的代码和有效价格。

您还可以将2)和3)组合在单个嵌套的"$addFields"中,如此示例链接中所示。

英文:

Maybe something like this:

db.collection.aggregate([
{
"$match": {
"_id": "abc"
}
},
{
"$addFields": {
"sales": {
"$filter": {
"input": "$sales",
"as": "s",
"cond": {
"$eq": [
"$$s.label",
1
]
}
}
}
}
},
{
"$addFields": {
"sales": {
"$map": {
"input": "$sales",
"as": "s",
"in": {
"$mergeObjects": [
"$$s",
{
codes: {
"$filter": {
"input": "$$s.codes",
"as": "c",
"cond": {
"$eq": [
"$$c.active",
true
]
}
}
},
prices: {
"$filter": {
"input": "$$s.prices",
"as": "p",
"cond": {
"$gt": [
"$$p.valid_from",
1
]
}
}
}
}
]
}
}
}
}
}
])

Playground

Explained:

  1. Match the document with _id="abc"
  2. addFields1 to filter only objects from sales[] having label=1
  3. addFields2/map/mergeObjects to filter only the active codes[] and valid prices[] inside the sales[] array.

You can also combine the 2) and 3) in single nested addFields as follow here

huangapple
  • 本文由 发表于 2023年4月6日 22:49:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75950883.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定