MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

$unwind um objeto na estrutura de agregação


Não é possível fazer o tipo de cálculo que você está descrevendo com a estrutura de agregação - e não porque não há $unwind método para não matrizes. Mesmo se os objetos person:value fossem documentos em uma matriz, $unwind não ajudaria.

A funcionalidade "agrupar por" (seja no MongoDB ou em qualquer banco de dados relacional) é feita no valor de um campo ou coluna. Agrupamos por valor de campo e soma/média/etc com base no valor de outro campo.

O exemplo simples é uma variante do que você sugere, campo de avaliações adicionado à coleção de artigos de exemplo, mas não como um mapa do usuário para a avaliação, mas como uma matriz como esta:
{ title : title of article", ...
  ratings: [
         { voter: "user1", score: 5 },
         { voter: "user2", score: 8 },
         { voter: "user3", score: 7 }
  ]
}

Agora você pode agregar isso com:
[ {$unwind: "$ratings"},
  {$group : {_id : "$ratings.voter", averageScore: {$avg:"$ratings.score"} } } 
]

Mas este exemplo estruturado como você o descreve ficaria assim:
{ title : title of article", ...
  ratings: {
         user1: 5,
         user2: 8,
         user3: 7
  }
}

ou mesmo isso:
{ title : title of article", ...
  ratings: [
         { user1: 5 },
         { user2: 8 },
         { user3: 7 }
  ]
}

Mesmo se você pudesse $unwind isso, não há nada para agregar aqui. A menos que você conheça a lista completa de todas as chaves (usuários) possíveis, você não pode fazer muito com isso. [*]

Um esquema de banco de dados relacional análogo ao que você tem seria:
CREATE TABLE T (
   user1: integer,
   user2: integer,
   user3: integer
   ...
);

Isso não é o que seria feito, em vez disso, faríamos isso:
CREATE TABLE T (
   username: varchar(32),
   score: integer
);

e agora agregamos usando SQL:

select username, avg(score) from T group by username;

Há uma solicitação de aprimoramento para o MongoDB que pode permitir que você faça isso na estrutura de agregação no futuro - a capacidade de projetar valores para chaves e vice-versa. Enquanto isso, sempre há map/reduce.

[*] Existe uma maneira complicada de fazer isso se você conhece todas as chaves exclusivas (você pode encontrar todas as chaves exclusivas com um método semelhante a este), mas se você conhece todas as chaves, você também pode executar uma sequência de consultas do form db.articles.find({"ratings.user1":{$exists:true}},{_id:0,"ratings.user1":1}) para cada userX que retornará todas as suas classificações e você pode somar e fazer a média delas de forma bastante simples, em vez de fazer uma projeção muito complexa que a estrutura de agregação exigiria.