Opis
Etap wejściowy subcollection(...) ułatwia wykonywanie złączeń nadrzędny-podrzędny
za pomocą wbudowanego pola __name__.
Do etapu subcollection(...) można dołączyć dodatkowe etapy, aby filtrować lub agregować zagnieżdżone dokumenty. Pamiętaj, że wszystkie odwołania do pól użyte na kolejnych etapach odnoszą się do dokumentów z zagnieżdżonej kolekcji, a nie do dokumentu nadrzędnego. Aby odwołać się do pól w zakresie nadrzędnym, najpierw użyj etapu let(...), aby zdefiniować zmienne, a potem odwołaj się do tych zmiennych w zakresie lokalnym.
Przykłady
Node.js
db.pipeline()
.collection("/restaurants")
.add_fields(subcollection("reviews")
.aggregate(average("rating").as("avg_rating"))
.toScalarExpression()
.as("avg_rating"))
Zachowanie
Etap subcollection(...) musi być używany w kontekście podzapytania. Używa __name__ (odniesienia do dokumentu) bieżącego dokumentu w zakresie nadrzędnym, aby określić, którą kolekcję podrzędną pobrać. Jeśli na przykład dokument nadrzędny to /restaurants/pizza-place, to zapytanie subcollection("reviews") zwraca wszystkie dokumenty z kolekcji /restaurants/pizza-place/reviews.
Jeśli odwołanie do dokumentu zostało zmienione lub nie można zdefiniować pola za pomocą właściwości __name__, ręcznie napisz złączenie w ten sposób:
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"))
jest nadal możliwe, ponieważ w zasadzie ten etap jest tylko uproszczoną wersją tego bardziej złożonego formatu łączenia.
W przypadku tych dokumentów:
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 });
To zapytanie pobiera każdą restaurację i podsumowuje jej opinie w nowym polu review_summary:
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();
i uzyskasz te wyniki:
{ 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 } },