La tua prima domanda era sulla strada giusta perché stavi utilizzando l'operatore di pipeline sbagliato.
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);
}
})
Naturalmente il $size
operatore lì richiede che tu abbia bisogno di una versione MongoDB 2.6 o successiva, cosa che probabilmente dovresti fare ormai, ma puoi comunque fare la stessa cosa senza l'operatore per misurare la lunghezza dell'array:
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);
}
})
Questo fa la stessa cosa contando i membri dell'array, ma invece dovresti $unwind
gli elementi dell'array per contarli. Quindi può ancora essere fatto ma non è così efficiente.
Inoltre è necessario gestire i casi in cui l'array è veramente vuoto ma presente a causa di come $unwind
tratta un array vuoto []
. Se non ci fosse contenuto, il documento che conteneva tale elemento sarebbe stato rimosso dai risultati. In modo simile dovresti usare $ifNull
per impostare un array in cui il documento non contenesse nemmeno un elemento per $unwind
per non generare un errore.
In realtà, se hai intenzione di eseguire questo tipo di query su base regolare, dovresti mantenere un campo "totale" nel documento piuttosto che cercare di calcolarlo prima. Usa $inc
operatore insieme a operazioni come $push
e $pull
per mantenere un conteggio della lunghezza dell'array corrente.
Ciò si discosta leggermente dalla filosofia generale di Waterline, ma hai già introdotto operazioni di aggregazione native e non è molto più difficile rendersi conto che stai ottenendo prestazioni migliori dall'utilizzo di operazioni native anche in altre aree.
Quindi con documenti come questi:
{
"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"
}
Ottieni esattamente i risultati che desideri in ogni caso:
{
"_id" : ObjectId("5494b79d7e22da84d53c8760"),
"name" : "The Doors",
"total" : 3
},
{
"_id" : ObjectId("5494b79d7e22da84d53c8761"),
"name" : "The Beatles",
"total" : 0
}