Първата ви заявка беше на прав път, обратно сте използвали грешния оператор на конвейер.
Artist.native(function(err,collection) {
collection.aggregate(
[
{ "$project": {
"_id": 1,
"name": 1,
"total": { "$size": "$dubs" }
}}
],
function(err,result) {
if (err) return res.serverError(err);
console.log(result);
}
})
Разбира се, $size
оператор там изисква да имате нужда от MongoDB 2.6 или по-нова версия, което вероятно трябва да направите досега, но все пак можете да направите същото без оператора за измерване на дължината на масива:
Artist.native(function(err,collection) {
collection.aggregate(
[
{ "$project": {
"_id": 1,
"name": 1,
"dubs": {
"$cond": [
{ "$eq": [ "$dubs", [] ] },
[0],
"$dubs"
]
}
}},
{ "$unwind": "$dubs" },
{ "$group": {
"_id": "$_id",
"name": { "$first": "$name" },
"total": {
"$sum": {
"$cond": [
{ "$eq": [ "$dubs", 0 ] },
0,
1
]
}
}
}}
],
function(err,result) {
if (err) return res.serverError(err);
console.log(result);
}
})
Това прави същото, като преброява членовете на масива, но вместо това ще трябва да $unwind
елементите на масива, за да ги преброим. Така че все още може да се направи, но не е толкова ефективно.
Освен това трябва да обработите случаите, когато масивът е наистина празен, но присъства поради начина, по който $unwind
третира празен масив []
. Ако няма съдържание, тогава документът, който съдържа такъв елемент, ще бъде премахнат от резултатите. По подобен начин ще трябва да използвате $ ifNull
за да зададете масив, където документът дори не съдържа елемент за $unwind
за да не доведе до грешка.
Наистина, ако възнамерявате да правите този вид заявка редовно, тогава трябва да поддържате поле "общо" в документа, вместо да се опитвате първо да го изчислите. Използвайте $inc
оператор заедно с операции като $pushкод>
и $pull
за да запазите сумата на текущата дължина на масива.
Това наистина се отдалечава малко от общата философия на Waterline, но вече сте въвели естествени операции за агрегиране и не е толкова трудно да осъзнаете, че получавате по-добра производителност от използването на естествени операции и в други области.
Така че с документи като тези:
{
"dubs": [{},{},{}],
"name": "The Doors",
"createdAt": "2014-12-15T15:24:26.216Z",
"updatedAt": "2014-12-15T15:24:26.216Z",
"id": "548efd2a436c850000353f4f"
},
{
"dubs": [],
"name": "The Beatles",
"createdAt": "2014-12-15T20:30:33.922Z",
"updatedAt": "2014-12-15T20:30:33.922Z",
"id": "548f44e90630d50000e2d61d"
}
Получавате точно резултатите, които искате във всеки случай:
{
"_id" : ObjectId("5494b79d7e22da84d53c8760"),
"name" : "The Doors",
"total" : 3
},
{
"_id" : ObjectId("5494b79d7e22da84d53c8761"),
"name" : "The Beatles",
"total" : 0
}