Das Aggregation Framework ist dafür ideal. Erwägen Sie, die folgende Pipeline auszuführen, um das gewünschte Ergebnis zu erhalten.
pipeline = [
{
"$match": {
"name": "james",
"books.year": 1990
}
},
{
"$project": {
"numberOfBooks": {
"$size": {
"$filter": {
"input": "$books",
"as": "el",
"cond": { "$eq": [ "$$el.year", 1990 ] }
}
}
}
}
}
];
db.collection.pipeline(pipeline);
Die obige Pipeline verwendet den neuen $filter
Operator, der für MongoDB 3.2 verfügbar ist, um ein Array zu erstellen, das die angegebene Bedingung erfüllt, d. h. er filtert äußere Elemente, die die Kriterien nicht erfüllen. Der anfängliche $match
Pipeline ist notwendig, um Dokumente herauszufiltern, die frühzeitig in die Aggregationspipeline gelangen, als Strategie zur Pipeline-Optimierung.
Der $size
Operator, der einen einzelnen Ausdruck als Argument akzeptiert, gibt Ihnen dann die Anzahl der Elemente im resultierenden Array, somit haben Sie Ihre gewünschte Buchanzahl.
Für eine alternative Lösung, die $filter
Operator, der in früheren Versionen nicht gefunden wurde, betrachten Sie die folgende Pipeline-Operation:
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);
Der $project
In der Pipeline-Phase wird das Bücher-Array so angepasst, dass Sie die Dokumente entfernen, die nicht das Jahr 1990 enthalten. Dies wird durch $setDifference
und $map
Betreiber.
Der $map
Der Operator erstellt im Wesentlichen ein neues Array-Feld, das Werte als Ergebnis der ausgewerteten Logik in einem Unterausdruck für jedes Element eines Arrays enthält. Der $setDifference
Der Operator gibt dann eine Menge mit Elementen zurück, die in der ersten Menge, aber nicht in der zweiten Menge vorkommen; d.h. führt eine relative Ergänzung des zweiten Satzes relativ zum ersten durch. In diesem Fall wird das letzte Bücher-Array zurückgegeben, das Elemente mit dem Jahr 1990 enthält, und anschließend den $size
berechnet die Anzahl der Elemente im resultierenden Array und gibt Ihnen so die Anzahl der Bücher.
Für eine Lösung, die den $unwind
Operator, wobei man bedenken sollte (dank dieser aufschlussreichen Antwort von @BlakesSeven in den Kommentaren):
Führen Sie als letzten Ausweg die folgende Pipeline aus:
pipeline = [
{
"$match": {
"name": "james",
"books.year": 1990
}
},
{ "$unwind": "$books" },
{
"$match": { "books.year": 1990 }
},
{
"$group": {
"_id": null
"count": { "$sum": 1 }
}
}
]
db.collection.pipeline(pipeline)