【问题标题】:Sum Quantity in Mongo Subdocument Based on Filter基于过滤器的Mongo子文档中的总和数量
【发布时间】:2021-06-29 14:13:32
【问题描述】:

我在 MongoDB 中有一个“装运”文档,它具有以下基本结构:

shipment {
   "id": "asdfasdfasdf",
   "shipDate": "2021-04-02",
   "packages": [
        {
            "id": "adfasdfasdfasdf",
            "contents": [
                {
                    "product": {
                        "id": "asdfasdfasdfasd"
                    },
                    "quantity": 10
                }
            ]
        }
    ]
}

请注意,“产品”存储为 DBRef。

我想查找自给定日期以来已发货的特定产品的总数量(基于产品 ID)。我认为这是应该遵循的适当逻辑:

  1. 匹配“shipDate”大于给定日期的货件。
  2. 查找“contents”中包含“id”与给定产品 ID 匹配的产品的条目
  3. 对每个匹配条目的“数量”值求和
  4. 返回总和

到目前为止,这是我为 Mongo 查询提出的:

db.shipment.aggregate([
    {$match: {"shipDate": {$gt: ISODate("2019-01-01")}}},
    {$unwind: "$packages"},
    {$unwind: "$packages.contents"},
    {$unwind: "$packages.contents.product"},
    {
        $project: {
            matchedProduct: {
                $filter: {
                    input: "$packages.contents.products",
                    as: "products",
                    cond: { 
                        "$eq": ["$products.id", ObjectId("5fb55eae3fb1bf783a4fa97f")]
                    }
                }
            }
        }
    }
])

查询有效,但似乎只返回满足 $match 条件且“products”值为 null 的所有条目。

我对 Mongo 查询很陌生,所以它可能是一个简单的解决方案。但是,我一直无法弄清楚如何返回匹配产品 ID 的“内容”数量字段的 $sum。

任何帮助将不胜感激,谢谢。

解决问题的查询

db.shipment.aggregate([
  {
    $match: {
      "shipDate": {$gte: ISODate("2019-01-01")},
      "packages.contents.product.$id": ObjectId("5fb55eae3fb1bf783a4fa98e")
    }
  },
  { $unwind: "$packages" },
  { $unwind: "$packages.contents" },
  { $unwind: "$packages.contents.product" },
  {
    $match: {
      "packages.contents.product.$id": ObjectId("5fb55eae3fb1bf783a4fa98e")
    }
  },
  {
    $group: {
      "_id": null,
      "total": {
        "$sum": "$packages.contents.quantity"
      }
    }
  }
])

【问题讨论】:

    标签: database mongodb filter aggregation


    【解决方案1】:

    演示 - https://mongoplayground.net/p/c3Ia9L47cJS

    使用 { $match: {"packages.contents.product.id": 1 } }, 按产品 ID 过滤记录。

    然后将它们分组并找到总数{ $group: {"_id": null,"total": { "$sum": "$packages.contents.quantity" } } }


    db.collection.aggregate([
      { $match: {"shipDate": "2021-04-02","packages.contents.product.id": 1 } },
      { $unwind: "$packages" },
      { $unwind: "$packages.contents" },
      { $match: { "packages.contents.product.id": 1 } },
      { $group: { "_id": null,"total": { "$sum": "$packages.contents.quantity" } } }
    ])
    

    在顶部 { $match: {"shipDate": "2021-04-02","packages.contents.product.id": 1 } } 为产品 ID 添加额外检查将仅过滤具有我们需要的产品 ID 的文档,因此查询会更快。


    选项 2

    演示 - https://mongoplayground.net/p/eo521luylsG

    db.collection.aggregate([
      { $match: { "shipDate": "2021-04-02", "packages.contents.product.id": 1 }},
      { $unwind: "$packages" },
      { $project: { contents: { $filter: { input: "$packages.contents", as: "contents",  cond: {"$eq": [  "$$contents.product.id",  1] }}}}},
      { $unwind: "$contents" },
      { $group: { "_id": null,  "total": { "$sum": "$contents.quantity" }}}
    ])
    

    【讨论】:

    • 感谢您的帮助!我用我的应用程序试了一下,查询工作但没有返回任何东西,尽管我正在搜索的 product.id 存在于内容数组中。我相信这是由存储为 DBRef 的产品引起的。示例:` "contents" : [ { "product" : DBRef("product", ObjectId("5fb55eae3fb1bf783a4fa982")), "quantity" : 36 } ]` 是否需要使用特殊语法来匹配 product.id什么时候是 DBRef?
    • @Kylep5587 能否将您的示例数据添加到mongoplayground.net 并分享链接,
    • @Kylep5587 试试"packages.contents.product.$id"docs.mongodb.com/manual/reference/database-references
    • 我尝试切换到 $id,但它仍然不匹配任何文档。这是 mongoplayground 上示例数据的链接:mongoplayground.net/p/MA1CTnGJJyP
    • 我在输入示例数据时忘记添加包。我对其进行了调整,并能够使用您的建议完成这项工作,并在展开内容的上方添加{ $unwind: "$packages" }。感谢大家的帮助!
    猜你喜欢
    • 2018-01-07
    • 1970-01-01
    • 2021-01-16
    • 1970-01-01
    • 2020-04-19
    • 1970-01-01
    • 2020-02-15
    • 2020-10-22
    • 1970-01-01
    相关资源
    最近更新 更多