sql >> Databasteknik >  >> NoSQL >> MongoDB

Matchande skick för sammanlagda antal Array-medlemmar

Felet beror på att det inte längre är en array efter att du $unwind och därför inte längre ett giltigt argument för $size .

Du verkar försöka "sammanfoga" ett par befintliga svar utan att förstå vad de gör. Det du verkligen vill ha här är $filter och $size

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

Eller "uppfinna hjulet på nytt" med $reduce :

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

Eller för vad du försökte göra med $unwind , du faktiskt $group igen för att "räkna" hur många matcher det var:

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

De två första formerna är de "optimala" för moderna MongoDB-miljöer. Det slutliga formuläret med $unwind och $group är en "legacy" konstruktion som verkligen inte har varit nödvändig för den här typen av operation sedan MongoDB 2.6, dock med några lite annorlunda operatörer.

I de två första jämför vi i princip field1 värdet för varje arrayelement medan det fortfarande är en array. Båda $filter och $reduce är moderna operatörer designade för att arbeta med en befintlig array på plats. Samma jämförelse görs på var och en med aggregeringen $eq operator som returnerar ett booleskt värde baserat på om de angivna argumenten är "lika" eller inte. I detta fall på varje arraymedlem till det förväntade värdet "a" .

I fallet med $filter , förblir matrisen faktiskt intakt förutom alla element som inte uppfyllde det angivna villkoret i "cond" tas bort från arrayen. Eftersom vi fortfarande har en "array" som utdata kan vi sedan använda $storlek operatorn för att mäta antalet arrayelement som finns kvar efter att filtervillkoret bearbetades.

$reduce å andra sidan arbetar genom arrayelementen och tillhandahåller ett uttryck över varje element och ett lagrat "ackumulator"-värde, som vi initierade med "initialValue" . I det här fallet samma $eq testet tillämpas inom $cond operatör. Detta är en "ternär" eller if/then/else villkorlig operator som tillåter att ett testat uttryck som returnerar ett booleskt värde returnerar then värde när true eller annat värde när false .

I det uttrycket returnerar vi 1 eller 0 respektive och ange det totala resultatet av att lägga till det returnerade värdet och den aktuella "ackumulatorn" "$$värde" med $sum operatör för att lägga ihop dessa.

Det slutliga formuläret används $unwind på arrayen. Vad detta faktiskt gör är att dekonstruera arraymedlemmarna för att skapa ett "nytt dokument" för varje arraymedlem och dess relaterade överordnade fält i originaldokumentet. Detta "kopierar" effektivt huvuddokumentet för varje arraymedlem.

När du $unwind dokumentens struktur ändras till en "plattare" form. Det är därför du sedan kan göra den efterföljande $match pipeline för att ta bort de omatchade dokumenten.

Detta för oss till $group som används för att "föra samman" all information som är relaterad till en gemensam nyckel. I det här fallet är det _id fältet i originaldokumentet, som naturligtvis kopierades till varje dokument som producerats av $unwind . När vi går tillbaka till denna "gemensamma nyckel" som ett enda dokument, kan vi "räkna" de återstående "dokumenten" som extraherats från arrayen med hjälp av $sum ackumulator.

Om vi ​​ville ha tillbaka den återstående "arrayen" kan du $push och bygg om arrayen med bara de återstående medlemmarna:

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

Men naturligtvis istället för att använda $size i ett annat steg i pipeline kan vi helt enkelt fortfarande "räkna" som vi redan gjorde med $summa




  1. mongodb sorteringsordning på _id

  2. Hur avgör man Redis minnesläcka?

  3. Mongodb Java-fråga för datumintervall

  4. Hur får man utskrifter för att felsöka kartan/förminska i Mongoid?