Din første forespørgsel var på rette vej, da du brugte den forkerte 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);
}
})
Selvfølgelig er $size
operatør der kræver, at du har brug for en MongoDB 2.6 eller nyere version, hvilket du nok burde gøre nu, men du kan stadig gøre det samme uden operatøren til at måle array-læ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 det samme ved at tælle medlemmerne af arrayet, men i stedet skal du $unwind
array-elementerne for at tælle dem. Så det kan stadig lade sig gøre, men er ikke så effektivt.
Derudover skal du håndtere de tilfælde, hvor arrayet virkelig er tomt, men til stede på grund af hvordan $unwind
behandler et tomt array []
. Hvis der ikke var noget indhold, ville dokumentet, der indeholdt et sådant element, blive fjernet fra resultaterne. På lignende måde skal du bruge $ ifNull
at indstille et array, hvor dokumentet ikke engang indeholdt et element for $unwind
for ikke at resultere i en fejl.
Virkelig, hvis du har til hensigt at udføre denne form for forespørgsel på regelmæssig basis, så bør du bevare et "total"-felt i dokumentet i stedet for at søge at beregne det først. Brug $inc
operatør sammen med operationer såsom $push
og $pull
for at holde en oversigt over den aktuelle array-længde.
Det bevæger sig lidt væk fra den generelle Waterline-filosofi, men du har allerede introduceret native aggregeringsoperationer, og det er ikke så meget mere besværligt at indse, at du får bedre ydeevne ved at bruge native operationer på andre områder også.
Så med dokumenter som disse:
{
"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 præcis de resultater, du ønsker i hvert enkelt tilfælde:
{
"_id" : ObjectId("5494b79d7e22da84d53c8760"),
"name" : "The Doors",
"total" : 3
},
{
"_id" : ObjectId("5494b79d7e22da84d53c8761"),
"name" : "The Beatles",
"total" : 0
}