我正在努力与mongodb中的聚合。我有以下类型的文件:
{
"_id": "xxxx",
"workHome": true,
"commute": true,
"tel": false,
"weekend": true,
"age":39
},
{
"_id": "yyyy",
"workHome": false,
"commute": true,
"tel": false,
"weekend": true,
"age":32
},
{
"_id": "zzzz",
"workHome": false,
"commute": false,
"tel": false,
"weekend": false,
"age":27
}
除此之外,我想通过文档中“true”的字段总数生成聚合。文档中总共有4个布尔字段,因此我希望查询将它们组合在一起以生成以下输出(例如,总共包含100个文档的集合中的示例):
0:20
1:30
2:10
3:20
4:20
这意味着:100个文件中有100个“全部为假”,30个文档“1x为真”,10个文档“2x为真”等等,总共“全部4个为真”。
有没有办法用$ aggregate语句执行此操作?现在我试图通过'真'值的$ sum来$ group,但是找不到让条件查询起作用的方法。
答案 0 :(得分:1)
因此,假设数据与“workHome”,“commute”,“tel”和“weekend”等所有相同的字段一致,那么您将继续进行“逻辑”评估,例如:
db.collection.aggregate([
{ "$project": {
"mapped": { "$map": {
"input": ["A","B","C","D"],
"as": "el",
"in": { "$cond": [
{ "$eq": [ "$$el", "A" ] },
"$workHome",
{ "$cond": [
{ "$eq": [ "$$el", "B" ] },
"$commute",
{ "$cond": [
{ "$eq": [ "$$el", "C" ] },
"$tel",
"$weekend"
]}
]}
]}
}}
}},
{ "$unwind": "$mapped" },
{ "$group": {
"_id": "$_id",
"size": { "$sum": { "$cond": [ "$mapped", 1, 0 ] } }
}},
{ "$group": {
"_id": "$size",
"count": { "$sum": 1 }
}},
{ "$sort": { "_id": 1 } }
])
从简单的样本中可以看出:
{ "_id" : 0, "count" : 1 }
{ "_id" : 2, "count" : 1 }
{ "_id" : 3, "count" : 1 }
为了解决这个问题,首先$map
运算符首先将字段的值转换为与字段本身相同长度的数组。这样做是通过$cond
将“输入”的每个元素与预期值进行比较,并将true
条件返回到匹配位置,或者转移到{{1}中嵌入的下一个条件这个"ternary"运算符的一部分。完成此操作直到满足所有逻辑匹配,并为第一个文档生成类似字段的值数组:
false
下一步是$unwind
数组元素以进行进一步比较。这会将每个数组元素的“反规范化”分离为单独的文档,并且在处理数组时通常需要在聚合管道中使用。
完成此操作后,将调用$group
管道阶段,以评估具有[true,true,false,true]
值的元素的“总数”。相同的true
三元组用于将逻辑$cond
条件转换为数值,并将其传送到$sum
累加器以进行添加。
由于true/false
中_id
中提供的“分组键”是原始文档$group
值,因此当前总计是_id
字段的每个文档。为了获得整个集合(或选择)上“计数”的总计,然后调用更进一步的true
阶段,其中分组键是每个匹配的$group
结果的返回“大小”文档。
在那里使用的true
累加器只为分组键上的每个匹配添加$sum
,从而“计算”每个匹配计数的出现次数。
最后$sort
匹配“key”的数量,以便为结果生成一些顺序。
为了记录,对于即将发布的MongoDB(写作时),这包括1
运算符,这是非常好的:
$filter
所以现在只有“两个”管道阶段与MongoDB 2.6及以上版本的原始语句做同样的事情。
因此,如果您自己的应用程序本身处于“开发”阶段,或者您对此感到好奇,那么请查看现在可以使用此功能的Development Branch releases。