sql >> Database >  >> NoSQL >> MongoDB

Geaggregeerde telling Array Leden overeenkomende voorwaarde

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 $size operator om het aantal array-elementen te meten dat overblijft nadat die filtervoorwaarde is verwerkt.

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




  1. Top 6-functies van HDFS - Een Hadoop HDFS-zelfstudie

  2. Mongo DB-aggregatie met array van objecten

  3. MongoDB:unieke beperking verwijderen

  4. Hoe MongoDB-aggregatie gebruiken voor paginering?