【问题标题】:MongoDB aggregate count of items in two arrays across different documents?MongoDB在不同文档的两个数组中汇总项目数?
【发布时间】:2015-11-16 07:29:53
【问题描述】:

这是我的 MongoDB 集合架构:

company: String
model: String
cons: [String] // array of tags that were marked as "cons"
pros: [String] // array of tags that were marked as "pros"

我需要聚合它,以便得到以下输出:

[{
  "_id": {
    "company": "Lenovo",
    "model": "T400"
  },
  "tags": {
    tag: "SomeTag"
    pros: 124 // number of times, "SomeTag" tag was found in "pros" array in `Lenovo T400`
    cons: 345 // number of times, "SomeTag" tag was found in "cons" array in `Lenovo T400`
  }
}...]

我尝试执行以下操作:

var aggParams = {};
aggParams.push({ $unwind: '$cons' });
aggParams.push({ $unwind: '$pros' });
aggParams.push({$group: {
  _id: {
    company: '$company',
    model: '$model',
    consTag: '$cons'
  },
  consTagCount: { $sum: 1 }
}});
aggParams.push({$group: {
  _id: {
    company: '$_id.company',
    model: '$_id.model',
    prosTag: '$pros'
  },
  prosTagCount: { $sum: 1 }
}});
aggParams.push({$group: {
  _id: {
    company:'$_id.company',
    model: '$_id.model'
  },
  tags: { $push: { tag: { $or: ['$_id.consTag', '$_id.prosTag'] }, cons: '$consTagCount', pros: '$prosTagCount'} }
}});

但我得到了以下结果:

{
  "_id": {
    "company": "Lenovo",
    "model": "T400"
  },
  "tags": [
    {
      "tag": false,
      "pros": 7
    }
  ]
}

使用aggregation 的正确方法是什么?

【问题讨论】:

  • 我们可以在这里假设“pros”或“cons”中的“tag”在任一数组中都是唯一的,或者实际上在两个数组中都是“唯一的”?当然是每个文件。
  • 正确,每个文档的标签都是唯一的(两个数组中的“唯一”)
  • 所以要完全清楚。 “SomeTag”只会在每个文档中出现一次,比如“pros”而不是“cons”?
  • @BlakesSeven 不,一个标签可能同时出现在“pros”和“cons”中
  • 两者都能出现就可以了。这里的关键元素是它永远不会多次出现在“专业人士”中。

标签: node.js mongodb mongoose mongodb-query aggregation-framework


【解决方案1】:

是的,考虑到有多个数组,这有点困难,如果你同时尝试两个数组,你最终会得到一个“笛卡尔条件”,其中一个数组乘以另一个数组的内容。

因此,只需在开头组合数组内容,这可能表明您应该如何存储数据:

Model.aggregate(
    [
        { "$project": {
            "company": 1,
            "model": 1,
            "data": {
                "$setUnion": [
                    { "$map": {
                        "input": "$pros",
                        "as": "pro",
                        "in": {
                            "type": { "$literal": "pro" },
                            "value": "$$pro"
                        }
                    }},
                    { "$map": {
                        "input": "$cons",
                        "as": "con",
                        "in": {
                            "type": { "$literal": "con" },
                            "value": "$$con"
                        }
                    }}
                ]
            }
        }},
        { "$unwind": "$data" }
        { "$group": {
            "_id": { 
                "company": "$company",
                "model": "$model",
                "tag": "$data.value"
            },
            "pros": { 
                "$sum": { 
                    "$cond": [
                        { "$eq": [ "$data.type", "pro" ] },
                        1,
                        0
                    ]
                }
            },
            "cons": { 
                "$sum": { 
                    "$cond": [
                        { "$eq": [ "$data.type", "con" ] },
                        1,
                        0
                    ]
                }
            }
        }
    ], 
    function(err,result) {

    }
)

因此,通过第一个 $project 阶段,$map 运算符将“类型”值添加到每个数组的每个项目中。这并不重要,因为无论如何所有项目都应该处理“唯一”,$setUnion 运算符将每个数组“包含”为单个数组。

如前所述,您可能应该首先以这种方式存储。

然后处理$unwind,后跟$group,其中每个“pros”和“cons”然后通过$cond评估它的匹配“type”,返回10匹配分别是true/false$sum 聚合累加器。

这为您提供了一个“逻辑匹配”,以根据指定的分组键计算聚合操作中的每个相应“类型”。

【讨论】:

  • 这里是输出:{ "_id": { "company": "Lenovo", "model": "T400", "tag": "Quality" }, "pros": 132, "cons": 324 }
  • @MikeVayvala 所以?重点是什么?这应该是您想要的,尽管您的“所需输出”不再是真正理想的。每个“pro”和“con”都按分组键计算。这基本上就是您所要求的。
猜你喜欢
  • 2015-11-16
  • 2015-11-16
  • 2020-06-26
  • 2018-06-06
  • 1970-01-01
  • 2014-09-30
  • 1970-01-01
  • 2012-01-19
  • 2023-03-05
相关资源
最近更新 更多