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