De fout is omdat het geen array meer is nadat u $unwind
en daarom niet langer een geldig argument voor $size
.
Het lijkt erop dat u een aantal bestaande antwoorden probeert te "samenvoegen" zonder te begrijpen wat ze doen. Wat je hier echt wilt, is $filter
en $size
db.collection.aggregate([
{ "$project": {
"total": {
"$size": {
"$filter": {
"input": "$Array",
"cond": { "$eq": [ "$$this.field1", "a" ] }
}
}
}
}}
])
Of "het wiel opnieuw uitvinden" met $reduce
:
db.collection.aggregate([
{ "$project": {
"total": {
"$reduce": {
"input": "$Array",
"initialValue": 0,
"in": {
"$sum": [
"$$value",
{ "$cond": [{ "$eq": [ "$$this.field1", "a" ] }, 1, 0] }
}
}
}
}}
])
Of voor wat je probeerde te doen met $unwind
, jij eigenlijk $group
nogmaals om te "tellen" hoeveel wedstrijden er waren:
db.collection.aggregate([
{ "$unwind": "$Array" },
{ "$match": { "Array.field1": "a" } },
{ "$group": {
"_id": "$_id",
"total": { "$sum": 1 }
}}
])
De eerste twee vormen zijn de "optimale" voor moderne MongoDB-omgevingen. Het definitieve formulier met $unwind
en $group
is een "legacy" constructie die sinds MongoDB 2.6 echt niet nodig is geweest voor dit soort bewerkingen, zij het met een aantal enigszins andere operators.
In die eerste twee vergelijken we in feite het veld1
waarde van elk array-element terwijl het nog steeds een array is. Beide $filter
en $reduce
zijn moderne operators die zijn ontworpen om te werken met een bestaande array. Dezelfde vergelijking wordt gedaan op elk met behulp van de aggregatie $eq
operator die een booleaanse waarde retourneert op basis van het feit of de gegeven argumenten "gelijk" zijn of niet. In dit geval op elk arraylid tot de verwachte waarde van "a"
.
In het geval van $filter
, blijft de array feitelijk intact, behalve voor alle elementen die niet voldeden aan de opgegeven voorwaarde in "cond"
worden uit de array verwijderd. Omdat we nog steeds een "array" als uitvoer hebben, kunnen we de
De $reduce
aan de andere kant werkt door de array-elementen en levert een expressie over elk element en een opgeslagen "accumulator" -waarde, die we hebben geïnitialiseerd met "initialValue"
. In dit geval dezelfde $eq
test wordt toegepast binnen de $cond
exploitant. Dit is een "ternair" of if/then/else
voorwaardelijke operator die een geteste uitdrukking toestaat die een booleaanse waarde retourneert om de then
. te retourneren waarde wanneer true
of de anders
waarde wanneer false
.
In die uitdrukking retourneren we 1
of 0
respectievelijk en geef het algemene resultaat van het optellen van die geretourneerde waarde en de huidige "accumulator" "$$value"
met de $sum
operator om deze bij elkaar op te tellen.
Het uiteindelijke formulier gebruikte $unwind
op de array. Wat dit in feite doet, is de arrayleden deconstrueren om een "nieuw document" te maken voor elk arraylid en de gerelateerde bovenliggende velden in het originele document. Dit "kopieert" effectief het hoofddocument voor elk arraylid.
Zodra u $unwind
de structuur van de documenten is veranderd in een "plattere" vorm. Dit is waarom je dan de volgende $match
pijplijnfase om de niet-overeenkomende documenten te verwijderen.
Dit brengt ons bij $group
die wordt toegepast om alle informatie met betrekking tot een gemeenschappelijke sleutel "weer bij elkaar te brengen". In dit geval is het de _id
veld van het originele document, dat natuurlijk is gekopieerd naar elk document dat is geproduceerd door de $unwind
. Als we teruggaan naar deze "gemeenschappelijke sleutel" als een enkel document, kunnen we de resterende "documenten" die uit de array zijn geëxtraheerd, "tellen" met behulp van de $sum
accumulator.
Als we de resterende "array" terug wilden hebben, dan kun je $duwen
en herbouw de array met alleen de resterende leden:
{ "$group": {
"_id": "$_id",
"Array": { "$push": "$Array" },
"total": { "$sum": 1 }
}}
Maar natuurlijk in plaats van $size
in een andere pijplijnfase kunnen we gewoon nog steeds "tellen" zoals we al deden met de $som