2017-06-15 41 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

相關問題