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

Gennemsnit af et underdokumentfelt på tværs af dokumenter i Mongo

Du skal bruge aggregeringsrammen. Aggregeringen ender med at se nogenlunde sådan her ud:

db.stack.aggregate([
  { $match: { "samples.key" : "test-key" } },
  { $unwind : "$samples" },
  { $match : { "samples.key" : "test-key" } },
  { $project : { "new_key" : "$samples.key", "new_value" : "$samples.value" } },
  { $group : { `_id` : "$new_key", answer : { $avg : "$new_value" } } }
])

Den bedste måde at tænke på aggregeringsrammen er som et samlebånd. Selve forespørgslen er et array af JSON-dokumenter, hvor hvert underdokument repræsenterer et andet trin i samlingen.

Trin 1:$match

Det første trin er et grundlæggende filter, som en WHERE-sætning i SQL. Vi placerer dette trin først for at bortfiltrere alle dokumenter, der ikke indeholder et array-element, der indeholder test-key . Ved at placere dette i begyndelsen af ​​pipelinen kan aggregeringen bruge indekser.

Trin 2:$unwind

Det andet trin, $unwind , bruges til at adskille hvert af elementerne i "samples"-arrayet, så vi kan udføre operationer på tværs af dem alle. Hvis du kører forespørgslen med bare det trin, vil du se, hvad jeg mener. Lang historie kort:

{ name : "bob", 
  children : [ {"name" : mary}, { "name" : "sue" } ] 
} 

bliver til to dokumenter :

{ name : "bob", children : [ { "name" : mary } ] }
{ name : "bob", children : [ { "name" : sue } ] }

Trin 3:$match

Det tredje trin, $match , er en nøjagtig kopi af den første $match scene, men har et andet formål. Da det følger $unwind , bortfiltrerer dette trin tidligere array-elementer, nu dokumenter, der ikke matcher filterkriterierne. I dette tilfælde opbevarer vi kun dokumenter, hvor samples.key = "test-key"

Trin 4:$project (valgfrit)

Det fjerde trin, $project , omstrukturerer dokumentet. I dette tilfælde trak jeg emnerne ud af arrayet, så jeg kunne referere dem direkte. Ved at bruge eksemplet ovenfor..

{ name : "bob", children : [ { "name" : mary } ] }

bliver til

{ new_name : "bob", new_child_name : mary }

Bemærk, at dette trin er helt valgfrit; senere stadier kunne fuldføres selv uden dette $project efter et par mindre ændringer. I de fleste tilfælde $project er helt kosmetisk; aggregeringer har adskillige optimeringer under hætten, således at man manuelt inkluderer eller ekskluderer felter i et $project burde ikke være nødvendigt.

Trin 5:$group

Til sidst $group det er der magien sker. _id værdsætte, hvad du vil "gruppere efter" i SQL-verdenen. Det andet felt siger et gennemsnit over den værdi, som jeg definerede i $project trin. Du kan nemt erstatte $sum for at udføre en sum, men en tælleoperation udføres typisk på følgende måde:my_count : { $sum : 1 } .

Det vigtigste at bemærke her er, at størstedelen af ​​det arbejde, der udføres, er at formatere dataene til et punkt, hvor det er nemt at udføre operationen.

Sidste bemærkning

Til sidst vil jeg bemærke, at dette ikke ville arbejde på de eksempeldata, der er leveret siden samples.value er defineret som tekst, der ikke kan bruges i aritmetiske operationer. Hvis du er interesseret, er ændring af typen af ​​et felt beskrevet her:MongoDB Sådan ændres typen af ​​et felt




  1. Kan MongoDB aggregeringsramme $group returnere en række værdier?

  2. MongoDB findOneAndDelete()

  3. Hvordan får man hele tællingen af ​​en mangustmodel?

  4. Mongoose automatisk stigning