首页 > 解决方案 > 每个文档级别的聚合 mongodb

问题描述

我有一份这样的文件清单

[{
        "_id": "5dbc95f921d7625303fe2369",
        "name": "John",
        "itemsPurchased": [{
                "offer": "o1",
                "items": ["p1"]
            },{
                "offer": "o1",
                "items": ["p1"]
            },
            {
                "offer": "o1",
                "items": ["p2"]
            },
            {
                "offer": "o2",
                "items": ["p1"]
            }, {
                "offer": "o7",
                "items": ["p1"]
            }
        ]
    },
    {
        "_id": "zbc95f921d7625303fe2363",
        "name": "Doe",
        "itemsPurchased": [{
                "offer": "o1",
                "items": ["p11"]
            },{
                "offer": "o1",
                "items": ["p11"]
            },
            {
                "offer": "o2",
                "items": ["p13"]
            },
            {
                "offer": "o1",
                "items": ["p22"]
            },
            {
                "offer": "o2",
                "items": ["p11"]
            }, {
                "offer": "o3",
                "items": ["p11"]
            }
        ]
    }
]

我正在尝试计算每个客户对独特产品的独特报价,期望结果如下:

[
  {
    "_id": "5dbc95f921d7625303fe2369",
    "name": "John",
    "offersAndProducts": {
      "o1":2,
      "o2":2,
      "o3":1
},
{
  "_id": "zbc95f921d7625303fe2363",
    "name": "Doe",
    "offersAndProducts": {
      "o1":2,
      "o2":1,
      "o7":1
    }
]

我想对每个文档应用聚合,在对 itemsPurchased 执行 $unwind 后,对项目应用 $group,然后提供以消除重复:

{ 
            "$group" : {
                "_id" : {
                    "item" : {
                        "$arrayElemAt" : [
                            "$itemsPurchased.item", 
                            0.0
                        ]
                    }, 
                    "count" : {
                        "$sum" : 1.0
                    }, 
                    "offer" : "$itemsPurchased.offer"
                }
            }
        }

然后,

{ 
            "$group" : {
                "_id" : "$_id.offer", 
                "count" : {
                    "$sum" : 1.0
                }
            }
        }

这为所有文档提供了一系列产品和优惠:

[
{o1:4,o2:3,o3:1,o7:1}
] 

但我需要它在文档级别。尝试过$addFeild,但是$unwind和 $match 运算符给出了无效错误。

还有其他方法可以实现吗?

标签: mongodbmongoosemongodb-queryaggregation-frameworkaggregate

解决方案


一般来说,它是$unwind一个数组的反模式,然后$group是原始的_id,因为大多数操作都可以在一个阶段直接在数组上完成。这是这样一个阶段的样子:

{$addFields:{
   offers:{$arrayToObject:{
      $map:{
         input:{$setUnion:"$itemsPurchased.offer"},
         as:"o",
         in:[
             "$$o", 
             {$size:{$setUnion:{$let:{
                vars:{items:{$filter:{
                    input:"$itemsPurchased",
                    cond:{$eq:["$$this.offer","$$o"]}
                }}},
                in:{$reduce:{
                    input:"$$items",
                    initialValue:[],
                    in:{$concatArrays:["$$value","$$items.items"]}
                }}
             }}}
          }]
      }
   }}
}}

这样做是创建一个数组,其中每个元素都是一个双元素数组(这是一种$arrayToObject可以转换为第一个元素是键名,第二个是值的对象的语法),输入是一组唯一的报价,对于每个我们累积一个产品数组,去掉重复项(用$setUnion),然后得到结果的大小。这对您的输入产生的结果是:

"offers" : {
    "o1" : 2,
    "o2" : 2,
    "o3" : 1
}

推荐阅读