现在,我已经在$ project,aggregate()和$ group上度过了一个周末,现在是时候再次投入自己的怜悯了。我尝试拨打电话,在那里我收回用户的总数,按性别分组(这是更容易的部分)并按年龄范围分组(这打败了我)。
我让它与一个小组合作:
Person.aggregate([
{
$match: {
user_id: id
}
},
{
$group: {
_id: '$gender',
total: { $sum: 1 }
}
}
])
.exec(function(err, result) {
etc...
从那以后,它会给我多少男人,一个漂亮的json输出中有多少女人。但是,如果我添加第二组,它似乎跳过了第一组并且在第二组中抛出了他的错误:
Person.aggregate([
{
$match: {
user_id: id
}
},
{
$group: {
_id: '$gender',
total: { $sum: 1 }
},
$group: {
_id: '$age',
age: { $gte: 21 },
age: { $lte: 30 },
total: { $sum: 1 }
}
}
])
.exec(function(err, result) {
etc...
它不喜欢$ gte或$ lte。如果我将它切换到$ project,那么它会执行gte / lte但是抛出大约$ sum或$ count。最重要的是,我无法找到如何构建多请求返回的任何示例。它只是"这是一件事,"但我不想做12个以上的电话只是为了获得所有人的年龄组。我希望输出看起来像这样:
[
{"_id":"male","total":49},
{"_id":"woman","total":42},
{"_id":"age0_10", "total": 1},
{"_id":"age11_20", "total": 5},
{"_id":"age21_30", "total": 15}
]
(我不知道如何让年龄的_id不是实际的年龄,这没有意义,b / c我不想要1517191919或其他什么,我想要一个可靠的名字,所以我知道在我的模板中输出它的位置。所以我知道_id:" $ age"不能给我我想要的东西,但我不知道如何得到我想要的东西。)
我唯一一次见过不止一件事,那就是$ match,$ group和$ project。但是如果$ project意味着我不能使用$ sum或$ count,我可以做多个$ group,如果可以的话,它的诀窍是什么?
答案 0 :(得分:1)
对于在不同年龄组中生成结果的情况,聚合框架的$cond
运算符可以在此处提供帮助。作为三元运算符,它采用逻辑结果(如果条件)并且可以返回true
(然后)或其他false
(其他)的值。在不同年龄组的情况下,你会"筑巢" else
条件下的调用,以满足每个范围,直到逻辑耗尽。
对于"性别"两个结果,一次性传球的整体情况并不实际。和"年龄"在分组中。虽然"可以" 完成,但唯一的方法是基本上累积数组中的所有数据,并再次为次要分组工作。这不是一个好主意,因为它在尝试保留数据时几乎总是会破坏16MB的实际BSON限制。因此通常需要更好的方法。
因此,在API支持的地方(你在nodejs之下,它确实如此),通常最好分别运行每个查询并组合结果。节点async
库具有以下功能:
async.concat(
[
// Gender aggregator
[
{ "$group": {
"_id": "$gender",
"total": { "$sum": 1 }
}}
],
// Age aggregator
[
{ "$group": {
"_id": {
"$cond": {
"if": { "$lte": [ "$age", 10 ] },
"then": "age_0_10",
"else": {
"$cond": {
"if": { "$lte": [ "$age", 20 ] },
"then": "age_11_20",
"else": {
"$cond": {
"if": { "$lte": [ "$age", 30 ] },
"then": "age_21_30",
"else": "age_over_30"
}
}
}
}
}
},
"total": { "$sum": 1 }
}}
]
],
function(pipeline,callback) {
Person.aggregate(pipeline,callback);
},
function(err,results) {
if (err) throw err;
console.log(results);
}
);
此处async.concat
的默认执行将启动并行运行的任务,因此两者可以同时在服务器上运行。输入数组中的每个管道都将传递给aggregate方法,然后返回结果并将输出数组合并到最终结果中。
最终结果是,您不仅可以将结果很好地键入年龄组,而且两个结果集似乎在同一个组合响应中,而不需要其他工作来合并内容。
这不仅方便,而且并行执行使得这更加节省时间,并且在用于返回结果的聚合方法上减少了(如果没有击败不可能的话)。