使用$ project和$ match的MongDB聚合

时间:2015-09-07 23:40:51

标签: mongodb mongodb-query aggregation-framework

我的文件类似于:

 {_id:'12345', timestamp:41123412451, value:1000}
 {_id:'98765', timestamp:41123498714, value:2000}
 {_id:'11122', timestamp:41287364245, value:3000}

我正在运行类似于以下的聚合查询:

[
{$match: {_id: {$ne: ObjectId('98765')}}},
{$project: { duration:{$subtract:[Date.now(),'$timestamp']}, value:1, _id:1}},
{$match:{value:{$gte:'duration'}}}
]

当我删除第二场$ match时,我会收到所有文件,除了' 98765' (如预期的那样)。但是,当我加入第二场$ match时,我没有得到任何文件。我试过了#duration;#39;和' $ duration'。当我更换'持续时间'在第二次匹配中,硬编码数字值为0,查询按预期工作(通过过滤掉值不大于或等于0的文档)。

[
{$match: {_id: {$ne: ObjectId('98765')}}},
{$project: { duration:{$subtract:[Date.now(),'$timestamp']}, value:1, _id:1}},
{$match:{value:{$gte:0}}}
]

似乎可能有一些"类型" mongo的问题是默默地忽略并且没有返回任何东西......有人可以通过上述聚合方法指出我可能缺少的东西吗?谢谢!

2 个答案:

答案 0 :(得分:2)

$match聚合阶段不起作用。就像标准查询一样,您无法将字段的值引用到查询运算符而不是另一个字段。有logical operators for comparison,它们与$project等阶段一起使用,如下所示:

{ "$project": { 
    "duration":{ "$subtract":[ Date.now(),"$timestamp"]}, 
    "value":1, 
    "matched": { "$gte": [ "$value", { "$subtract":[ Date.now(),"$timestamp"]} ] }
}},
{ "$match": { "matched": true } }

但实际上,$redact和“可选地”投射新字段可能会更好:

{ "$redact": {
    "$cond": {
        "if": {  "$gte": [ "$value", { "$subtract":[ Date.now(),"$timestamp"]} ] },
        "then": "$$KEEP",
        "else": "$$PRUNE"
    }
}},
{ "$project": { 
    "duration": { "$subtract":[ Date.now(),"$timestamp"] }, 
    "value":1
}},

所以$redact以“逻辑”的方式工作,与$match以“物理”方式工作的方式相同,并且可以包含可以对其进行计算值或直接字段比较的表达式文档以“过滤”内容。

通过这样做,基本上也很方便,因为$project的成本实际上仅限于满足条件的那些文档,如果你甚至需要输出中的计算值,那么在哪种情况下你可以完全跳过它。

答案 1 :(得分:0)

你在第二场比赛中犯了一个简单的错误。

 {$match:{value:{$gte:'duration'}}}

应该是:

{$match:{value:{$gte:'$duration'}}}

'持续时间'是由聚合管道的第二阶段生成的变量。因此,它应在第3阶段称为“ $ duration ”。