我有一种情况,我需要根据一个数值来执行一个组,该数组值总结了一个字段值的出现次数。然后过滤计数并准备结果,以便可以根据条件显示它们。基本上,如果您只是使用find函数,文档将转换回它们的呈现方式。由于matchedDocuments数组中收集的项目数量,我遇到临时文档太大的问题。关于如何改进这一点的任何建议都会有所帮助。
db.collection1.aggregate([
{
'$unwind': '$arrayOfValues'
}, {
'$group': {
'_id': '$arrayOfValues',
'x_count': {
$sum: {
$cond: [{
$eq: ['$field.value', 'x']
},
1, 0
]
}
},
'y_count': {
$sum: {
$cond: [{
$eq: ['$field.value', 'y']
},
1, 0
]
}
},
'matchedDocuments': {
'$push': '$$CURRENT'
}
}
},
{'$match': {'$or': [{'x_count': {'$gte': 2}}, {'y_count': { '$gte': 1}}]}},
{'$unwind': '$matchedDocuments'},
{
'$group': {
'_id': '$matchedDocuments.key',
'document': {
'$last': '$$CURRENT.matchedDocuments'
}
}
}
], {
allowDiskUse: true
})
以下是一些示例文档和基于上述标准的预期结果:
// Sample documents
{ "_id" : ObjectId("5407c76b7b1c276c74f90524"), "field" : "x", "arrayOfValues" : [ "a", "b", "c" ] }
{ "_id" : ObjectId("5407c76b7b1c276c74f90525"), "field" : "x", "arrayOfValues" : [ "b", "c" ] }
{ "_id" : ObjectId("5407c76b7b1c276c74f90526"), "field" : "z", "arrayOfValues" : [ "a" ] }
{ "_id" : ObjectId("5407c76b7b1c276c74f90527"), "field" : "x", "arrayOfValues" : [ "a", "c" ] }
{ "_id" : ObjectId("5407c76b7b1c276c74f90528"), "field" : "z", "arrayOfValues" : [ "b" ] }
{ "_id" : ObjectId("5407c76b7b1c276c74f90529"), "field" : "y", "arrayOfValues" : [ "k" ] }
// Expected Result
[
{ "_id" : ObjectId("5407c76b7b1c276c74f90524"), "field" : "x", "arrayOfValues" : [ "a", "b", "c" ] }
{ "_id" : ObjectId("5407c76b7b1c276c74f90525"), "field" : "x", "arrayOfValues" : [ "b", "c" ] }
{ "_id" : ObjectId("5407c76b7b1c276c74f90527"), "field" : "x", "arrayOfValues" : [ "a", "c" ] }
{ "_id" : ObjectId("5407c76b7b1c276c74f90529"), "field" : "y", "arrayOfValues" : [ "k" ] }
]
答案 0 :(得分:2)
我认为最终你要从一个查询中得到一点点过多,因为显然这里最大的问题是尝试存储数组元素来源的所有原始文档,同时尝试聚合总数。
对我来说,我只会尝试确定文档中的哪些条件会导致匹配,然后发出单独的查询以获取实际文档。您可以调整下面的聚合以尝试返回文档,但我认为这样做很可能会失败,因为它与使用数组的方式相反。
这个过程通常会更有效地进行匹配,使你首先选择#34;选择你感兴趣的元素并匹配条件"其次,"使用自然分组条件而不是依赖条件总和"。
var cursor = db.collection.aggregate([
{ "$match": { "field": { "$in": ["x", "y"] } } },
{ "$unwind": "$arrayOfValues" },
{ "$group": {
"_id": {
"elem": "$arrayOfValues",
"field": "$field"
},
"count": { "$sum": 1 }
}},
{ "$match": {
"$or": [
{ "_id.field": "x", "count": { "$gte": 2 } },
{ "_id.field": "y", "count": { "$gte": 1 } }
]
}},
{ "$group": {
"_id": "$_id.field",
"values": { "$push": "$_id.elem" }
}}
])
var query = { "$or": [] };
cursor.forEach(function(doc) {
query["$or"].push({
"field": doc._id,
"arrayOfValues": { "$in": doc.values }
});
});
db.collection.find(query)
对于记录,在给定提供的数据的情况下,查询应如下所示:
{
"$or" : [
{
"field" : "x",
"arrayOfValues" : {
"$in" : [
"c",
"b",
"a"
]
}
},
{
"field" : "y",
"arrayOfValues" : {
"$in" : [
"k"
]
}
}
]
}
只需查找" field"的值即可满足基本逻辑。你感兴趣的,所以至少从可能的结果中消除所有其他的。那么你基本上想要计算每个"字段"下每个数组元素的计数。值和测试满足所需事件的位置。
这可能会或者可能不会以相反的方式发挥作用,但此处的示例显示了" arrayOfValues"因此,作为第二级分组是有意义的。
如前所述,我认为基本上要求的东西太多了#34;东西"将所有父文档信息分成一个数组,用于每个" arrayOfValues"因为这超出了合理模式的基本原则,其中这种关系自然地存储为单独的文档。所以这里的最终原则就是找到"条件"匹配那些最终结果的文件。
然后针对集合发布转换后的查询,其中将返回满足从先前分析确定的条件的所有文档。在一天结束时,转移"提取"匹配文档到另一个查询,而不是尝试存储匹配在数组中的文档。
这似乎是最合乎逻辑且可扩展的方法,但如果您倾向于在此类结果中使用您的数据,那么您应该考虑重新设计您的架构以更好地适应这种情况。但是这里确实没有足够的具体信息来进一步评论。