MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

$unwind ein Objekt im Aggregationsframework

Es ist nicht möglich, die Art von Berechnung, die Sie beschreiben, mit dem Aggregations-Framework durchzuführen - und es ist nicht weil es kein $unwind gibt Methode für Nicht-Arrays. Selbst wenn die person:value-Objekte Dokumente in einem Array wären, $unwind würde nicht helfen.

Die Funktion „Gruppieren nach“ (ob in MongoDB oder in einer relationalen Datenbank) wird für den Wert eines Felds oder einer Spalte ausgeführt. Wir gruppieren nach Feldwert und Summe/Durchschnitt/usw. basierend auf dem Wert eines anderen Felds.

Ein einfaches Beispiel ist eine Variante dessen, was Sie vorschlagen, das Bewertungsfeld wurde der Beispielartikelsammlung hinzugefügt, aber nicht als Karte vom Benutzer zur Bewertung, sondern als Array wie dieses:

{ title : title of article", ...
  ratings: [
         { voter: "user1", score: 5 },
         { voter: "user2", score: 8 },
         { voter: "user3", score: 7 }
  ]
}

Jetzt können Sie dies aggregieren mit:

[ {$unwind: "$ratings"},
  {$group : {_id : "$ratings.voter", averageScore: {$avg:"$ratings.score"} } } 
]

Aber dieses Beispiel, das so strukturiert ist, wie Sie es beschreiben, würde folgendermaßen aussehen:

{ title : title of article", ...
  ratings: {
         user1: 5,
         user2: 8,
         user3: 7
  }
}

oder sogar das:

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

Selbst wenn Sie $unwind könnten dazu gibt es hier nichts zu aggregieren. Wenn Sie nicht die vollständige Liste aller möglichen Schlüssel (Benutzer) kennen, können Sie damit nicht viel anfangen. [*]

Ein analoges relationales DB-Schema zu dem, was Sie haben, wäre:

CREATE TABLE T (
   user1: integer,
   user2: integer,
   user3: integer
   ...
);

Das würden wir nicht tun, stattdessen würden wir Folgendes tun:

CREATE TABLE T (
   username: varchar(32),
   score: integer
);

und jetzt aggregieren wir mit SQL:

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

Es gibt eine Erweiterungsanforderung für MongoDB, die Ihnen dies in Zukunft im Aggregationsframework ermöglichen könnte – die Fähigkeit, Werte auf Schlüssel und umgekehrt zu projizieren. Inzwischen gibt es immer map/reduce.

[*] Es gibt einen komplizierten Weg, dies zu tun, wenn Sie alle eindeutigen Schlüssel kennen (Sie können alle eindeutigen Schlüssel mit einer ähnlichen Methode finden), aber wenn Sie alle Schlüssel kennen, können Sie auch einfach eine Folge von Abfragen von ausführen Form db.articles.find({"ratings.user1":{$exists:true}},{_id:0,"ratings.user1":1}) für jeden Benutzer X, der alle seine Bewertungen zurückgibt, und Sie können sie einfach genug summieren und mitteln, anstatt eine sehr komplexe Projektion durchzuführen, die das Aggregations-Framework erfordern würde.