Рамката за агрегиране е идеална за такива. Помислете за изпълнение на следния конвейер, за да получите желания резултат.
pipeline = [
{
"$match": {
"name": "james",
"books.year": 1990
}
},
{
"$project": {
"numberOfBooks": {
"$size": {
"$filter": {
"input": "$books",
"as": "el",
"cond": { "$eq": [ "$$el.year", 1990 ] }
}
}
}
}
}
];
db.collection.pipeline(pipeline);
Горният канал използва новия $filterкод>
оператор, наличен за MongoDB 3.2, за да създаде масив, който отговаря на определеното условие, т.е. филтрира външни елементи, които не отговарят на критериите. Първоначалният $matchкод>
тръбопроводът е необходим за филтриране на документи, които попадат в тръбопровода за агрегиране на ранен етап като стратегия за оптимизиране на конвейера.
$size
оператор, който приема един израз като аргумент, след което ви дава броя на елементите в резултантния масив, като по този начин имате желания брой книги.
За алтернативно решение, което не използва $ филтър
оператор, който не е намерен в по-ранни версии, разгледайте следната конвейерна операция:
pipeline = [
{
"$match": {
"name": "james",
"books.year": 1990
}
},
{
"$project": {
"numberOfBooks": {
"$size": {
"$setDifference": [
{
"$map": {
"input": "$books",
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el.year", 1990 ] },
"$$el",
false
]
}
}
},
[false]
]
}
}
}
}
];
db.collection.pipeline(pipeline);
$project
етапът на тръбопровод включва монтиране на масива от книги, така че да премахнете документите, които нямат годината 1990. Това е възможно чрез $setDifference
и $mapкод>
оператори.
$mapкод>
операторът по същество създава ново поле за масив, което съдържа стойности в резултат на изчислената логика в подизраз към всеки елемент от масив. $setDifferenceкод>
след това операторът връща набор с елементи, които се появяват в първия набор, но не и във втория набор; т.е. извършва относително допълнение на втория набор спрямо първия. В този случай той ще върне окончателния масив от книги, който има елементи с година 1990 и впоследствие $size
изчислява броя на елементите в резултантния масив, като по този начин ви дава броя на книгите.
За решение, което използва $unwind
оператор, като се има предвид, че (благодарение на този проницателен отговор от @BlakesSeven в коментарите):
и в краен случай изпълнете следния конвейер:
pipeline = [
{
"$match": {
"name": "james",
"books.year": 1990
}
},
{ "$unwind": "$books" },
{
"$match": { "books.year": 1990 }
},
{
"$group": {
"_id": null
"count": { "$sum": 1 }
}
}
]
db.collection.pipeline(pipeline)