2017-06-15 24 views
0

的文档是简单的:聚集带的NodeJS驱动程序 - 由字段是否为空分组

[ 
    {'id': '1', 'type': 'a', 'startedAt': '2017-06-11'}, 
    {'id': '2', 'type': 'b', 'startedAt': ''}, 
    {'id': '3', 'type': 'b', 'startedAt': '2017-06-11'} 
] 

和预期的汇总结果:

[ 
    {'type': 'a', 'started': true, 'count': 1}, 
    {'type': 'b', 'started': true, 'count': 1}, 
    {'type': 'b', 'started': false, 'count': 1} 
] 

如何获得上面的MongoDB的NodeJS驱动的结果?

我试图像下面,但它没有工作(“开始”总是空):

db.collection('docs').group(
     {'type': '$type', 'started': { 
     $cond: [{$eq: ['$startedAt': '']}, false, true ] 
     }}, 
     {}, 
     {'total': 0}, 
     'function(curr, result) {result.total++}' 
    ) 

回答

2

您使用.aggregate()这里,而不是.group(),这是一个不同的功能完全:

db.collection('docs').aggregate([ 
    { "$group": { 
    "_id": { 
     "type": "$type", 
     "started": { 
     "$gt": [ "$startedAt", "" ] 
     } 
    }, 
    "count": { "$sum": 1 } 
    }} 
],function(err, results) { 
    console.log(results); 
}) 

当满足条件时,$gt运算符返回true。在这种情况下,字符串中的任何内容都是“大于”空字符串。

如果该字段实际上“根本不存在”,那么我们可以使用$ifNull进行修改。如果该属性实际上不存在,或者以其他方式评估为null,则会给出默认值。

db.collection('docs').aggregate([ 
    { "$group": { 
    "_id": { 
     "type": "$type", 
     "started": { 
     "$gt": [ { "$ifNull": [ "$startedAt", ""] }, "" ] 
     } 
    }, 
    "count": { "$sum": 1 } 
    }} 
],function(err, results) { 
    console.log(results); 
}) 

这将产生:

{ "_id" : { "type" : "b", "started" : true }, "count" : 1 } 
{ "_id" : { "type" : "b", "started" : false }, "count" : 1 } 
{ "_id" : { "type" : "a", "started" : true }, "count" : 1 } 

可以事后可选$project从正在内的结果_id更改的字段,但你真的不应该,因为这意味着通过业绩的额外传球,当无论如何,您可以轻松访问这些值。

所以只是对结果.map()

console.log(
    results.map(function(r) { 
    return { type: r._id.type, started: r._id.started, count: r.count } 
}) 
); 

但随着$project

db.collection('docs').aggregate([ 
    { "$group": { 
    "_id": { 
     "type": "$type", 
     "started": { 
     "$gt": [ { "$ifNull": [ "$startedAt", ""] }, "" ] 
     } 
    }, 
    "tcount": { "$sum": 1 } 
    }}, 
    { "$project": { 
    "_id": 0, 
    "type": "$_id.type", 
    "started": "$_id.started", 
    "count": "$tcount" 
    }} 
],function(err, results) { 
    console.log(results); 
}) 

在你想要的格式所得

{ "type" : "b", "started" : true, "count" : 1 } 
{ "type" : "b", "started" : false, "count" : 1 } 
{ "type" : "a", "started" : true, "count" : 1 } 

对于refe伦斯,与.group()正确的用法是:

db.collection('docs').group(
    function(doc) { 
     return { 
     "type": doc.type, 
     "started": (
      (doc.hasOwnProperty('startedAt') ? doc.startedAt : "") > "" 
     ) 
     } 
    }, 
    [], 
    { "count": 0 }, 
    function(curr,result) { 
     result.count += 1 
    }, 
    function(err,results) { 
     console.log(results); 
    } 
); 

将返回:

[ 
    { "type" : "a", "started" : true, "count" : 1 }, 
    { "type" : "b", "started" : false, "count" : 1 }, 
    { "type" : "b", "started" : true, "count" : 1 } 
] 

但你真的应该没有用,既然.group()依赖于运行速度比你可以做慢得多的JavaScript评价.aggregate()

+0

这个答案是全面的,更不用说它的作品。我将坚持使用.aggregate + .map,并单独保留$ project或.group。 @ neil-lunn,谢谢! – Timathon

相关问题