sql >> Database teknologi >  >> NoSQL >> MongoDB

Aggregeret Count Array Members Matching Condition

Fejlen skyldes, at det ikke længere er et array efter du $unwind og derfor ikke længere et gyldigt argument til $size .

Du ser ud til at forsøge at "sammenflette" et par eksisterende svar uden at forstå, hvad de gør. Det, du virkelig ønsker her, er $filter og $size

db.collection.aggregate([
  { "$project": {
    "total": {
      "$size": {
        "$filter": {
          "input": "$Array",
          "cond": { "$eq": [ "$$this.field1", "a" ] }
        }
      }
    }
  }}
])

Eller "genopfind hjulet" ved hjælp af $reduce :

db.collection.aggregate([
  { "$project": {
    "total": {
      "$reduce": {
        "input": "$Array",
        "initialValue": 0,
        "in": {
          "$sum": [
            "$$value", 
            { "$cond": [{ "$eq": [ "$$this.field1", "a" ] }, 1, 0] }
        }
      }
    }
  }}
])

Eller for det, du prøvede at gøre med $unwind , du faktisk $group igen for at "tælle" hvor mange kampe der var:

db.collection.aggregate([
  { "$unwind": "$Array" },
  { "$match": { "Array.field1": "a" } },
  { "$group": {
    "_id": "$_id",
    "total": { "$sum": 1 }
  }}
])

De to første former er de "optimale" for moderne MongoDB-miljøer. Den endelige formular med $unwind og $group er en "legacy" konstruktion, som virkelig ikke har været nødvendig for denne type operation siden MongoDB 2.6, dog med nogle lidt forskellige operatører.

I de første to sammenligner vi grundlæggende field1 værdien af ​​hvert array-element, mens det stadig er et array. Begge $filter og $reduce er moderne operatører designet til at arbejde med et eksisterende array på plads. Den samme sammenligning udføres på hver enkelt ved hjælp af aggregeringen $eq operator som returnerer en boolesk værdi baseret på om de angivne argumenter er "lige" eller ej. I dette tilfælde på hvert array-medlem til den forventede værdi af "a" .

I tilfælde af $filter , forbliver arrayet faktisk intakt bortset fra alle elementer, der ikke opfyldte den leverede betingelse i "cond" fjernes fra arrayet. Da vi stadig har et "array" som output, kan vi derefter bruge $størrelse operatør for at måle antallet af array-elementer tilbage, efter at filterbetingelsen blev behandlet.

$reduce på den anden side arbejder gennem array-elementerne og leverer et udtryk over hvert element og en lagret "akkumulator"-værdi, som vi initialiserede med "initialValue" . I dette tilfælde den samme $eq testen anvendes inden for $cond operatør. Dette er en "ternær" eller if/then/else betinget operator, som tillader et testet udtryk, som returnerer en boolesk værdi, for at returnere then værdi, når sand eller else værdi når false .

I det udtryk returnerer vi 1 eller 0 og angiv det overordnede resultat af at tilføje den returnerede værdi og den aktuelle "akkumulator" "$$værdi" med $sum operatør for at lægge disse sammen.

Den endelige formular brugte $unwind på arrayet. Hvad dette faktisk gør, er at dekonstruere array-medlemmerne for at skabe et "nyt dokument" for hvert array-medlem og dets relaterede overordnede felter i det originale dokument. Dette "kopierer" effektivt hoveddokumentet for hvert array-medlem.

Når du $unwind strukturen af ​​dokumenterne ændres til en "fladere" form. Dette er grunden til, at du så kan lave den efterfølgende $match pipeline for at fjerne de umatchede dokumenter.

Dette bringer os til $group som anvendes til at "samle tilbage" al information relateret til en fælles nøgle. I dette tilfælde er det _id felt i det originale dokument, som naturligvis blev kopieret ind i hvert dokument, der blev produceret af $unwind . Når vi går tilbage til denne "fælles nøgle" som et enkelt dokument, kan vi "tælle" de resterende "dokumenter" udtrukket fra arrayet ved hjælp af $sum akkumulator.

Hvis vi ville have det resterende "array" tilbage, så kan du $push og genopbyg arrayet med kun de resterende medlemmer:

  { "$group": {
    "_id": "$_id",
    "Array": { "$push": "$Array" },
    "total": { "$sum": 1 }
  }}

Men selvfølgelig i stedet for at bruge $size i en anden pipeline-fase kan vi simpelthen stadig "tælle", som vi allerede gjorde med $sum




  1. Bedste måde at modellere et afstemningssystem i MongoDB

  2. Sådan bruger du $regex i mongodb aggregeringsforespørgsel inden for $match

  3. Implementering af goMongoDB-lignende Query-udtryksobjektevaluering

  4. Opbygning og installation af MongoDB C++ driver i OS X