Aggregeringsramverket är idealiskt för sådana. Överväg att köra följande pipeline för att få önskat resultat.
pipeline = [
{
"$match": {
"name": "james",
"books.year": 1990
}
},
{
"$project": {
"numberOfBooks": {
"$size": {
"$filter": {
"input": "$books",
"as": "el",
"cond": { "$eq": [ "$$el.year", 1990 ] }
}
}
}
}
}
];
db.collection.pipeline(pipeline);
Ovanstående pipeline använder det nya $filter
operatör tillgänglig för MongoDB 3.2 för att producera en array som uppfyller det specificerade villkoret, dvs den filtrerar yttre element som inte uppfyller kriterierna. Den initiala $match
pipeline är nödvändig för att filtrera bort dokument som kommer in i aggregeringspipelinen tidigt som en pipelineoptimeringsstrategi.
$size
operatorn som accepterar ett enstaka uttryck som argument ger dig sedan antalet element i den resulterande arrayen, så att du har önskat bokantal.
För en alternativ lösning som inte använder $ filter
operatör som inte hittades i tidigare versioner, överväg följande pipelineoperation:
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
pipeline-stadiet innebär att man anpassar bokarrayen så att man tar bort de dokument som inte har årtalet 1990. Detta görs möjligt genom $setDifference
och $map
operatörer.
$map
Operatören skapar i huvudsak ett nytt arrayfält som innehåller värden som ett resultat av den utvärderade logiken i ett underuttryck till varje element i en array. $setDifference
operatorn returnerar sedan en uppsättning med element som förekommer i den första uppsättningen men inte i den andra uppsättningen; dvs. utför ett relativt komplement av den andra uppsättningen relativt den första. I det här fallet kommer den att returnera den slutliga bokarrayen som har element med år 1990 och därefter $size
beräknar antalet element i den resulterande arrayen, vilket ger dig bokantalet.
För en lösning som använder $avslappnade
operatör, med tanke på att (tack vare detta insiktsfulla svar från @BlakesSeven i kommentarerna):
och som en sista utväg, kör följande pipeline:
pipeline = [
{
"$match": {
"name": "james",
"books.year": 1990
}
},
{ "$unwind": "$books" },
{
"$match": { "books.year": 1990 }
},
{
"$group": {
"_id": null
"count": { "$sum": 1 }
}
}
]
db.collection.pipeline(pipeline)