Votre première requête était sur la bonne voie puisque vous utilisiez le mauvais opérateur de pipeline.
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);
}
})
Bien sûr, le $size
l'opérateur nécessite que vous ayez besoin d'une version MongoDB 2.6 ou supérieure, ce que vous devriez probablement faire maintenant, mais vous pouvez toujours faire la même chose sans l'opérateur pour mesurer la longueur du tableau :
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);
}
})
Cela fait la même chose en comptant les membres du tableau, mais à la place, vous auriez besoin de $unwind
les éléments du tableau afin de les compter. Donc, cela peut toujours être fait mais n'est pas aussi efficace.
De plus, vous devez gérer les cas où le tableau est vraiment vide mais présent en raison de la façon dont $unwind
traite un tableau vide []
. S'il n'y avait pas de contenu, le document qui contenait un tel élément serait supprimé des résultats. De la même manière, vous devrez utiliser $ifNull
pour définir un tableau où le document ne contient même pas d'élément pour $unwind
pour ne pas générer d'erreur.
Vraiment, si vous avez l'intention de faire ce genre de requête de manière régulière, vous devez conserver un champ "total" dans le document plutôt que de chercher à le calculer en premier. Utilisez le $inc
opérateur avec des opérations telles que $push
et $pull
pour conserver un décompte de la longueur actuelle du tableau.
Cela s'éloigne un peu de la philosophie générale de Waterline, mais vous avez déjà introduit des opérations d'agrégation natives et il n'est pas beaucoup plus difficile de réaliser que vous obtenez de meilleures performances en utilisant des opérations natives dans d'autres domaines également.
Donc, avec des documents comme ceux-ci :
{
"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"
}
Vous obtenez exactement les résultats souhaités dans chaque cas :
{
"_id" : ObjectId("5494b79d7e22da84d53c8760"),
"name" : "The Doors",
"total" : 3
},
{
"_id" : ObjectId("5494b79d7e22da84d53c8761"),
"name" : "The Beatles",
"total" : 0
}