Beschreibung
Mit der Eingabephase subcollection(...) lassen sich Parent-Child-Verknüpfungen mithilfe des integrierten Felds __name__ ganz einfach ausführen.
An die Phase subcollection(...) können weitere Phasen angehängt werden, um die verschachtelten Dokumente zu filtern oder zu aggregieren. Alle Feldverweise in nachfolgenden Phasen beziehen sich auf die Dokumente aus der verschachtelten Sammlung und nicht auf das übergeordnete Dokument. Wenn Sie auf Felder im übergeordneten Bereich verweisen möchten,
definieren Sie zuerst Variablen mit der Phase let(...) und verweisen Sie dann
im lokalen Bereich auf diese Variablen.
Beispiele
Node.js
db.pipeline()
.collection("/restaurants")
.add_fields(subcollection("reviews")
.aggregate(average("rating").as("avg_rating"))
.toScalarExpression()
.as("avg_rating"))
Verhalten
Die Phase subcollection(...) muss im Kontext einer Unterabfrage verwendet werden. Sie verwendet __name__ (die Dokumentreferenz) des aktuellen Dokuments im übergeordneten Bereich, um zu bestimmen, welche untergeordnete Sammlung abgerufen werden soll. Wenn das übergeordnete Dokument beispielsweise /restaurants/pizza-place ist, gibt
subcollection("reviews") alle Dokumente aus der
/restaurants/pizza-place/reviews Sammlung zurück.
Wenn die Dokumentreferenz umbenannt wurde oder es nicht möglich ist, ein Feld mit __name__ zu definieren, kann die Verknüpfung manuell geschrieben werden:
Node.js
db.pipeline()
.collection("/restaurants")
.let(field("__name__").as("restaurant_name"))
.add_fields(db.pipeline()
.collectionGroup("reviews")
.where(field("__name__").parent().equals(variable("restaurant_name")))
.aggregate(average("rating").as("avg_rating"))
.toScalarExpression()
.as("avg_rating"))
Das ist weiterhin möglich, da diese Phase im Grunde nur eine syntaktische Vereinfachung dieses komplexeren Verknüpfungsformats ist.
Für die folgenden Dokumente:
Node.js
const restaurant1 = db.collection("restaurants").document("pizza-place");
const restaurant2 = db.collection("restaurants").document("urban-bite");
const restaurant3 = db.collection("restaurants").document("nacho-house");
await restaurant1.create({ name: "Pizza Place" });
await restaurant2.create({ name: "Urban Bite" });
await restaurant3.create({ name: "Nacho House" });
await restaurant1.collection("reviews").doc("1").create({ rating: 5 });
await restaurant1.collection("reviews").doc("1").create({ rating: 2 });
await restaurant2.collection("reviews").doc("1").create({ rating: 3 });
await restaurant2.collection("reviews").doc("1").create({ rating: 4 });
await restaurant2.collection("reviews").doc("1").create({ rating: 5 });
Mit der folgenden Abfrage wird jedes Restaurant abgerufen und seine Rezensionen in einem neuen Feld review_summary zusammengefasst:
Node.js
const results = await db.pipeline()
.collectionGroup("restaurants")
.add_fields(subcollection("reviews")
.aggregate(
countAll().as("review_count"),
average("rating").as("avg_rating"))
.asScalarExpression()
.as("review_summary"))
.execute();
und liefert die folgenden Ergebnisse:
{ name: "Pizza Place", review_summary: { review_count: 2, avg_rating: 3.5 } },
{ name: "Urban Bite", review_summary: { review_count: 3, avg_rating: 4.0 } },
{ name: "Nacho House", review_summary: { review_count: 0, avg_rating: null } },