Din första förfrågan var på rätt väg. Då använde du fel pipeline-operatör.
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);
}
})
Naturligtvis $size
operatören där kräver att du behöver en MongoDB 2.6 eller senare version, vilket du förmodligen borde göra vid det här laget, men du kan fortfarande göra samma sak utan operatören för att mäta arraylängden:
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);
}
})
Det gör samma sak genom att räkna medlemmarna i arrayen, men istället skulle du behöva $unwind
arrayelementen för att räkna dem. Så det kan fortfarande göras men är inte lika effektivt.
Dessutom måste du hantera de fall där arrayen verkligen är tom men närvarande på grund av hur $unwind
behandlar en tom array []
. Om det inte fanns något innehåll skulle dokumentet som innehöll ett sådant element tas bort från resultaten. På liknande sätt skulle du behöva använda $ ifNull
för att ställa in en array där dokumentet inte ens innehöll ett element för $unwind
för att inte resultera i ett fel.
Om du verkligen tänker göra den här typen av frågor regelbundet, bör du behålla ett "totalt" fält i dokumentet istället för att försöka beräkna det först. Använd $inc
operatör tillsammans med operationer som $push
och $pull
för att hålla koll på den aktuella arraylängden.
Det går lite bort från den allmänna Waterline-filosofin, men du har redan introducerat inbyggda aggregeringsoperationer och det är inte så mycket jobbigt att inse att du får bättre prestanda av att använda inbyggda operationer i andra områden också.
Så med dokument som dessa:
{
"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"
}
Du får exakt de resultat du vill ha i varje fall:
{
"_id" : ObjectId("5494b79d7e22da84d53c8760"),
"name" : "The Doors",
"total" : 3
},
{
"_id" : ObjectId("5494b79d7e22da84d53c8761"),
"name" : "The Beatles",
"total" : 0
}