简体   繁体   English

Mongo 聚合和 $group 嵌套数组与 $lookup

[英]Mongo aggregate and $group nested array with $lookup

I have the following Product Schema: (partial, using mongoose)我有以下产品架构:(部分,使用猫鼬)

 attributes: [
      {
        set: {
          ref: 'AttributeSet',
          type: Schema.Types.ObjectId
        },
        items: [
          {
            attribute: {
              ref: 'Attributes',
              type: Schema.Types.ObjectId
            },
            values: [
              {
                ref: 'AttributeValues',
                type: Schema.Types.ObjectId
              }
            ]
          }
        ],
        _id: 0
      }
    ],

example document 1: (partial)示例文档 1:(部分)

"attributes" : [
        {
            "set" : ObjectId("5ccc079c846de44116182890"),
            "items" : [
                {
                    "values" : [
                        ObjectId("5ccc0900846de441161828a1")
                    ],
                    "_id" : ObjectId("5dee638d72fa520f53d0d1c4"),
                    "attribute" : ObjectId("5ccc0900846de441161828a0")
                },
                {
                    "values" : [
                        ObjectId("5ccc0a51846de441161828cc")
                    ],
                    "_id" : ObjectId("5dee638d72fa520f53d0d1c3"),
                    "attribute" : ObjectId("5ccc0a51846de441161828cb")
                },
                {
                    "values" : [
                        ObjectId("5ccc0c7d846de44116182906")
                    ],
                    "_id" : ObjectId("5dee638d72fa520f53d0d1c2"),
                    "attribute" : ObjectId("5ccc0c7d846de44116182904")
                },
                {
                    "values" : [
                        ObjectId("5ccc0d64846de44116182911")
                    ],
                    "_id" : ObjectId("5dee638d72fa520f53d0d1c1"),
                    "attribute" : ObjectId("5ccc0d64846de4411618290f")
                },
                {
                    "values" : [
                        ObjectId("5ccc079f846de44116182892")
                    ],
                    "_id" : ObjectId("5def6acf66910405e07e1e9f"),
                    "attribute" : ObjectId("5ccc079f846de44116182891")
                }
            ]
        }
    ]

example document 2: (partial)示例文档 2:(部分)

"attributes" : [
        {
            "set" : ObjectId("5ccc079c846de44116182890"), 
            "items" : [
                {
                    "values" : [
                        ObjectId("5ccc079f846de44116182892")
                    ], 
                    "_id" : ObjectId("5dee635c72fa520f53d0d1c0"), 
                    "attribute" : ObjectId("5ccc079f846de44116182891")
                }, 
                {
                    "values" : [
                        ObjectId("5ccc0900846de441161828a2")
                    ], 
                    "_id" : ObjectId("5dee635c72fa520f53d0d1bf"), 
                    "attribute" : ObjectId("5ccc0900846de441161828a0")
                }, 
                {
                    "values" : [
                        ObjectId("5ccc0ea4846de44116182941")
                    ], 
                    "_id" : ObjectId("5dee635c72fa520f53d0d1be"), 
                    "attribute" : ObjectId("5ccc0ea4846de44116182940")
                }, 
                {
                    "values" : [
                        ObjectId("5ccc08ba846de4411618289c")
                    ], 
                    "_id" : ObjectId("5def56c537e877042d5abeb5"), 
                    "attribute" : ObjectId("5ccc08ba846de4411618289a")
                }, 
                {
                    "values" : [
                        ObjectId("5ccc09ca846de441161828aa"), 
                        ObjectId("5ccc09ca846de441161828a9")
                    ], 
                    "_id" : ObjectId("5def56c537e877042d5abeb4"), 
                    "attribute" : ObjectId("5ccc09ca846de441161828a7")
                }
            ]
        }
    ], 

I want to aggregate and find all products that have attributes and then group the attributes in the output.我想聚合并找到所有具有属性的产品,然后在输出中对这些属性进行分组。

Pipeline:管道:

db.getCollection("products").aggregate(
  [
    { $unwind: "$attributes" },
    {
      $group: {
        _id: "$attributes",
        attributes: { $first: "$attributes.items" }
      }
    },
    { $unwind: "$attributes" },
    {
      $lookup: {
        from: "attributes",
        let: { attribute: "$attributes.attribute" },
        pipeline: [
          {
            $match: {
              $expr: {
                $eq: ["$_id", "$$attribute"]
              }
            }
          },
          { $project: { display_name: 1, _id: 1 } }
        ],
        as: "attrs"
      }
    },
    {
      $lookup: {
        from: "attributevalues",
        let: { attribute: "$attributes.values" },
        pipeline: [
          {
            $match: {
              $expr: {
                $in: ["$_id", "$$attribute"]
              }
            }
          }
        ],
        as: "values"
      }
    },
    { $project: { attrs: 1, values: 1, _id: 0 } },
    {
      $group: { _id: "$attrs", items: { $push: "$values" }, total: { $sum: 1 } }
    }
  ],
  {
    allowDiskUse: true
  }
);

Pipeline output:管道输出:

[{ 
    "_id" : [
        {
            "_id" : ObjectId("5ccc079f846de44116182891"), 
            "display_name" : "Caliber (cal.)"
        }
    ], 
    "items" : [
        [
            {
                "_id" : ObjectId("5ccc079f846de44116182892"), 
                "sort_order" : NumberInt(0),
                "label" : "12", 
                "attribute_id" : ObjectId("5ccc079f846de44116182891")
            }
        ], 
        [
            {
                "_id" : ObjectId("5ccc079f846de44116182892"), 
                "sort_order" : NumberInt(0),
                "label" : "12", 
                "attribute_id" : ObjectId("5ccc079f846de44116182891")
            }
        ]
    ], 
    "total" : 2.0
},
{
    "_id" : [
        {
            "_id" : ObjectId("5ccc0900846de441161828a0"),
            "display_name" : "Mechanism"
        }
    ],
    "items" : [
        [
            {
                "_id" : ObjectId("5ccc0900846de441161828a2"),
                "sort_order" : NumberInt(1),
                "label" : "Inaction",
                "attribute_id" : ObjectId("5ccc0900846de441161828a0")
            }
        ],
        [
            {
                "_id" : ObjectId("5ccc0900846de441161828a1"),
                "sort_order" : NumberInt(0),
                "label" : "Gas",
                "attribute_id" : ObjectId("5ccc0900846de441161828a0")
            }
        ]
    ],
    "total" : 2.0
}]

Problem is that ex in 1st element in the array, I have a duplicate inside the items array.问题是 ex 在数组的第一个元素中,我在items数组中有一个重复items

This is the desired output:这是所需的输出:

[{
    "_id" : [
        {
            "_id" : ObjectId("5ccc079f846de44116182891"),
            "display_name" : "Caliber (cal.)"
        }
    ],
    "items" : [
        [
            {
                "_id" : ObjectId("5ccc079f846de44116182892"),
                "sort_order" : NumberInt(0),
                "label" : "12",
                "attribute_id" : ObjectId("5ccc079f846de44116182891"),
                "total": 'current _id total, in this case it should be 2'
            }
        ],
        ...other items goes below, grouped as above
    ]
}]

Add the solution to group the values by attribute and values and count the occurrences followed by look up and pushing all the values for the attribute with their count.添加解决方案以按属性和值对值进行分组并计算出现次数,然后查找并推送属性的所有值及其计数。

db.products.aggregate(
[
   {"$unwind":"$attributes"},
   {"$unwind":"$attributes.items"},
   {"$replaceRoot":{"newRoot":"$attributes.items"}},
   {"$unwind":"$values"},
   {"$group":{
      "_id":{"attribute":"$attribute","values":"$values"},
      "total":{"$sum":1}
   }},
   {"$lookup":{
      "from":"attributes",
      "let":{"attribute":"$_id.attribute"},
      "pipeline":[
        {"$match":{"$expr":{"$eq":["$_id","$$attribute"]}}},
        {"$project":{"display_name":1,"_id":1}}],
      "as":"attrs"
   }},
   {"$lookup":{
      "from":"attributevalues",
      "localField":"_id.values",
      "foreignField":"_id",
      "as":"values"
   }},
   {"$unwind":"$values"},
   {"$addFields":{"values.total":"$total"}},
   {"$group":{
     "_id":{"$arrayElemAt":["$attrs", 0]},
     "values":{"$push":"$values"}
   }}
])

Use the below aggregation query.使用以下聚合查询。 Use $addToSet to keep unique values.使用 $addToSet 保持唯一值。

db.products.aggregate(
 [
  {"$unwind":"$attributes"},
  {"$unwind":"$attributes.items"},
  {"$replaceRoot":{"newRoot":"$attributes.items"}},
  {"$unwind":"$values"},
  {"$group":{
     "_id":"$attribute",
     "values":{"$addToSet":"$values"},
     "total":{"$sum":1}
  }},
  {"$lookup":{
     "from":"attributes",
     "let":{"attribute":"$_id"},
     "pipeline":[
       {"$match":{"$expr":{"$eq":["$_id","$$attribute"]}}},
       {"$project":{"display_name":1,"_id":1}}],
     "as":"attrs"
  }},
  {"$addFields":{"attrs":{"$arrayElemAt":["$attrs", 0]}},
  {"$lookup":{
     "from":"attributevalues",
     "localField":"values",
     "foreignField":"_id",
     "as":"values"
   }}
])

Old answer旧答案

You could use below aggregation query.您可以使用以下聚合查询。 I tried to clean up your current query and change to group only by values field.我试图清理您当前的查询并更改为仅按值字段分组。

Something like就像是

db.products.aggregate(
[
  {"$unwind":"$attributes"},
  {"$unwind":"$attributes.items"},
  {"$replaceRoot":{"newRoot":"$attributes.items"}},
  {"$unwind":"$values"},
  {"$group":{
    "_id":"$values",
    "items":{"$first":"$$ROOT"},
    "total":{"$sum":1}
  }},
  {"$lookup":{
    "from":"attributes",
    "let":{"attribute":"$items.attribute"},
    "pipeline":[
      {"$match":{"$expr":{"$eq":["$_id","$$attribute"]}}},
      {"$project":{"display_name":1,"_id":1}}],
    "as":"attrs"
  }},
  {"$lookup":{
     "from":"attributevalues",
     "localField":"items.values",
     "foreignField":"_id",
     "as":"values"
  }},
  {"$unwind":"$values"},
  {"$group":{
    "_id":{"$arrayElemAt":["$attrs", 0]},
    "values":{"$push":"$values"},
    "total":{"$first":"$total"}
  }},
  {"$addFields":{"_id":0, "attribute":"$_id"}}
])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM