Você precisará usar a estrutura de agregação. A agregação vai ficar mais ou menos assim:
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" } } }
])
A melhor maneira de pensar na estrutura de agregação é como uma linha de montagem. A consulta em si é uma matriz de documentos JSON, onde cada subdocumento representa uma etapa diferente na montagem.
Etapa 1:$match
A primeira etapa é um filtro básico, como uma cláusula WHERE no SQL. Colocamos esta etapa primeiro para filtrar todos os documentos que não contêm um elemento de matriz contendo
test-key
. Colocar isso no início do pipeline permite que a agregação use índices. Etapa 2:$descontrair
A segunda etapa,
$unwind
, é usado para separar cada um dos elementos na matriz "amostras" para que possamos realizar operações em todos eles. Se você executar a consulta com apenas essa etapa, verá o que quero dizer. Resumindo:{ name : "bob",
children : [ {"name" : mary}, { "name" : "sue" } ]
}
torna-se dois documentos:
{ name : "bob", children : [ { "name" : mary } ] }
{ name : "bob", children : [ { "name" : sue } ] }
Etapa 3:$match
A terceira etapa,
$match
, é uma duplicata exata do primeiro $match
palco, mas tem um propósito diferente. Como segue $unwind
, esse estágio filtra os elementos anteriores da matriz, agora documentos, que não correspondem aos critérios do filtro. Nesse caso, mantemos apenas documentos em que samples.key = "test-key"
Etapa 4:$project (opcional)
A quarta etapa,
$project
, reestrutura o documento. Nesse caso, retirei os itens do array para poder referenciá-los diretamente. Usando o exemplo acima.. { name : "bob", children : [ { "name" : mary } ] }
torna-se
{ new_name : "bob", new_child_name : mary }
Observe que esta etapa é totalmente opcional; etapas posteriores podem ser concluídas mesmo sem este
$project
após algumas pequenas alterações. Na maioria dos casos $project
é inteiramente cosmético; agregações têm inúmeras otimizações sob o capô, como incluir ou excluir campos manualmente em um $project
não deve ser necessário. Etapa 5:$grupo
Finalmente,
$group
é onde a mágica acontece. O _id
valorize o que você estará "agrupando" no mundo SQL. O segundo campo está dizendo para calcular a média sobre o valor que defini no $project
Passo. Você pode substituir facilmente $sum
para realizar uma soma, mas uma operação de contagem normalmente é feita da seguinte maneira:my_count : { $sum : 1 }
. A coisa mais importante a ser observada aqui é que a maior parte do trabalho que está sendo feito é formatar os dados até um ponto em que a execução da operação seja simples.
Observação final
Por fim, gostaria de observar que isso não trabalhe nos dados de exemplo fornecidos desde
samples.value
é definido como texto, que não pode ser usado em operações aritméticas. Se você estiver interessado, a alteração do tipo de um campo está descrita aqui:MongoDB Como alterar o tipo de um campo