sql >> Base de Datos >  >> NoSQL >> MongoDB

Promediar un campo de subdocumento en documentos en Mongo

Deberá utilizar el marco de agregación. La agregación terminará luciendo algo como esto:

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" } } }
])

La mejor manera de pensar en el marco de agregación es como una línea de montaje. La consulta en sí es una matriz de documentos JSON, donde cada subdocumento representa un paso diferente en el ensamblaje.

Paso 1:$coincidir

El primer paso es un filtro básico, como una cláusula WHERE en SQL. Colocamos este paso primero para filtrar todos los documentos que no contienen un elemento de matriz que contiene test-key . Colocar esto al comienzo de la canalización permite que la agregación use índices.

Paso 2:$relajarse

El segundo paso, $unwind , se usa para separar cada uno de los elementos en la matriz de "muestras" para que podamos realizar operaciones en todos ellos. Si ejecuta la consulta con solo ese paso, verá lo que quiero decir. Para resumir:

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

se convierte en dos documentos:

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

Paso 3:$coincidir

El tercer paso, $match , es un duplicado exacto del primer $match etapa, pero tiene un propósito diferente. Dado que sigue a $unwind , esta etapa filtra elementos de matriz anteriores, ahora documentos, que no coinciden con los criterios de filtro. En este caso, conservamos solo los documentos donde samples.key = "test-key"

Paso 4:$proyecto (Opcional)

El cuarto paso, $project , reestructura el documento. En este caso, saqué los elementos de la matriz para poder hacer referencia a ellos directamente. Usando el ejemplo anterior...

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

se convierte

{ new_name : "bob", new_child_name : mary }

Tenga en cuenta que este paso es completamente opcional; las etapas posteriores podrían completarse incluso sin este $project después de algunos cambios menores. En la mayoría de los casos $project es enteramente cosmético; las agregaciones tienen numerosas optimizaciones bajo el capó, de modo que se incluyen o excluyen campos manualmente en un $project no debería ser necesario.

Paso 5:$grupo

Finalmente, $group es donde ocurre la magia. El _id valore lo que "agrupará" en el mundo SQL. El segundo campo dice promediar sobre el valor que definí en el $project paso. Puede sustituir fácilmente $sum para realizar una suma, pero una operación de conteo generalmente se realiza de la siguiente manera:my_count : { $sum : 1 } .

Lo más importante a tener en cuenta aquí es que la mayor parte del trabajo que se realiza es formatear los datos hasta un punto en el que realizar la operación es simple.

Nota final

Por último, quería señalar que esto no trabaje en los datos de ejemplo proporcionados desde samples.value se define como texto, que no se puede utilizar en operaciones aritméticas. Si está interesado, aquí se describe cómo cambiar el tipo de un campo:MongoDB Cómo cambiar el tipo de un campo