Sua primeira consulta estava no caminho certo, você estava usando o operador de pipeline errado.
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);
}
})
Claro que o
$size
O operador requer que você precise de uma versão do MongoDB 2.6 ou superior, o que você provavelmente deve fazer agora, mas ainda pode fazer a mesma coisa sem o operador para medir o comprimento do 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);
}
})
Isso faz a mesma coisa contando os membros da matriz, mas, em vez disso, você precisaria
$unwind
os elementos do array para contá-los. Portanto, ainda pode ser feito, mas não é tão eficiente. Além disso, você precisa lidar com os casos em que a matriz está realmente em branco, mas presente devido à forma como
$unwind
trata um array vazio []
. Se não houvesse conteúdo, o documento que continha tal elemento seria removido dos resultados. De forma semelhante, você precisaria usar $ ifNull
para definir uma matriz em que o documento nem mesmo continha um elemento para $unwind
para não resultar em erro. Realmente, se você pretende fazer esse tipo de consulta regularmente, deve manter um campo "total" no documento em vez de tentar calculá-lo primeiro. Use o
$inc
operador junto com operações como $push
e $pull
para manter uma contagem do comprimento atual da matriz. Isso se afasta um pouco da filosofia geral do Waterline, mas você já introduziu operações de agregação nativa e não é muito difícil perceber que você está obtendo melhor desempenho usando operações nativas em outras áreas também.
Então, com documentos como estes:
{
"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"
}
Você obtém exatamente os resultados que deseja em cada caso:
{
"_id" : ObjectId("5494b79d7e22da84d53c8760"),
"name" : "The Doors",
"total" : 3
},
{
"_id" : ObjectId("5494b79d7e22da84d53c8761"),
"name" : "The Beatles",
"total" : 0
}