Du måste använda aggregeringsramverket. Aggregeringen kommer att se ut ungefär så här:
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" } } }
])
Det bästa sättet att tänka på aggregeringsramverket är som ett löpande band. Själva frågan är en uppsättning JSON-dokument, där varje underdokument representerar ett annat steg i sammansättningen.
Steg 1:$match
Det första steget är ett grundläggande filter, som en WHERE-sats i SQL. Vi placerar detta steg först för att filtrera bort alla dokument som inte innehåller ett array-element som innehåller test-key
. Genom att placera detta i början av pipelinen kan aggregeringen använda index.
Steg 2:$unwind
Det andra steget, $unwind
, används för att separera vart och ett av elementen i "samples"-arrayen så att vi kan utföra operationer över dem alla. Om du kör frågan med bara det steget kommer du att förstå vad jag menar. Lång historia kort:
{ name : "bob",
children : [ {"name" : mary}, { "name" : "sue" } ]
}
blir två dokument :
{ name : "bob", children : [ { "name" : mary } ] }
{ name : "bob", children : [ { "name" : sue } ] }
Steg 3:$match
Det tredje steget, $match
, är en exakt dubblett av den första $match
skede, men har ett annat syfte. Eftersom det följer $unwind
, filtrerar detta steg bort tidigare arrayelement, nu dokument, som inte matchar filterkriterierna. I det här fallet behåller vi endast dokument där samples.key = "test-key"
Steg 4:$project (valfritt)
Det fjärde steget, $project
, omstrukturerar dokumentet. I det här fallet drog jag ut objekten ur arrayen så att jag kunde referera till dem direkt. Med exemplet ovan...
{ name : "bob", children : [ { "name" : mary } ] }
blir
{ new_name : "bob", new_child_name : mary }
Observera att detta steg är helt valfritt; senare steg skulle kunna slutföras även utan detta $project
efter några mindre ändringar. I de flesta fall $project
är helt kosmetisk; aggregationer har många optimeringar under huven så att manuellt inkludera eller exkludera fält i ett $project
borde inte vara nödvändigt.
Steg 5:$group
Slutligen, $group
det är där magin händer. _id
värdesätt vad du kommer att "gruppera efter" i SQL-världen. Det andra fältet säger att medelvärde över värdet som jag definierade i $project
steg. Du kan enkelt ersätta $sum
för att utföra en summa, men en räkneoperation görs vanligtvis på följande sätt:my_count : { $sum : 1 }
.
Det viktigaste att notera här är att majoriteten av arbetet som görs är att formatera data till en punkt där det är enkelt att utföra operationen.
Sista anmärkning
Till sist ville jag notera att detta inte skulle göra arbeta med exempeldata som tillhandahålls sedan samples.value
definieras som text, som inte kan användas i aritmetiska operationer. Om du är intresserad, ändring av typ av ett fält beskrivs här:MongoDB Hur man ändrar typ av ett fält