No es posible realizar el tipo de cálculo que está describiendo con el marco de agregación, y no porque no hay $unwind
método para no arreglos. Incluso si los objetos person:value fueran documentos en una matriz, $unwind
no ayudaría.
La funcionalidad de "agrupar por" (ya sea en MongoDB o en cualquier base de datos relacional) se realiza sobre el valor de un campo o columna. Agrupamos por valor de campo y suma/promedio/etc. en función del valor de otro campo.
El ejemplo simple es una variante de lo que sugiere, el campo de calificaciones agregado a la colección de artículos de ejemplo, pero no como un mapa del usuario a la calificación, sino como una matriz como esta:
{ title : title of article", ...
ratings: [
{ voter: "user1", score: 5 },
{ voter: "user2", score: 8 },
{ voter: "user3", score: 7 }
]
}
Ahora puede agregar esto con:
[ {$unwind: "$ratings"},
{$group : {_id : "$ratings.voter", averageScore: {$avg:"$ratings.score"} } }
]
Pero este ejemplo estructurado como usted lo describe se vería así:
{ title : title of article", ...
ratings: {
user1: 5,
user2: 8,
user3: 7
}
}
o incluso esto:
{ title : title of article", ...
ratings: [
{ user1: 5 },
{ user2: 8 },
{ user3: 7 }
]
}
Incluso si pudieras $unwind
esto, no hay nada que agregar aquí. A menos que conozca la lista completa de todas las claves posibles (usuarios), no puede hacer mucho con esto. [*]
Un esquema de base de datos relacional análogo al que tiene sería:
CREATE TABLE T (
user1: integer,
user2: integer,
user3: integer
...
);
Eso no es lo que se haría, sino que haríamos esto:
CREATE TABLE T (
username: varchar(32),
score: integer
);
y ahora agregamos usando SQL:
select username, avg(score) from T group by username;
Hay una solicitud de mejora para MongoDB que puede permitirle hacer esto en el marco de agregación en el futuro:la capacidad de proyectar valores a claves y viceversa. Mientras tanto, siempre hay map/reduce.
[*] Hay una manera complicada de hacer esto si conoce todas las claves únicas (puede encontrar todas las claves únicas con un método similar a este), pero si conoce todas las claves, también puede ejecutar una secuencia de consultas del formulario db.articles.find({"ratings.user1":{$exists:true}},{_id:0,"ratings.user1":1})
para cada usuarioX que devolverá todas sus calificaciones y puede sumarlas y promediarlas de manera bastante simple en lugar de hacer una proyección muy compleja que requeriría el marco de agregación.