Descrizione
La fase di input subcollection(...) semplifica l'esecuzione di unioni padre-figlio
utilizzando il campo __name__ integrato.
È possibile concatenare fasi aggiuntive alla fase subcollection(...) per eseguire
il filtraggio o l'aggregazione dei documenti nidificati. Tieni presente che tutti i riferimenti ai campi utilizzati nelle fasi successive si riferiscono ai documenti della raccolta nidificata, non al documento principale. Per fare riferimento ai campi nell'ambito principale,
utilizza prima la fase let(...) per definire le variabili, poi
fai riferimento a queste variabili nell'ambito locale.
Esempi
Node.js
db.pipeline()
.collection("/restaurants")
.add_fields(subcollection("reviews")
.aggregate(average("rating").as("avg_rating"))
.toScalarExpression()
.as("avg_rating"))
Comportamento
La fase subcollection(...) deve essere utilizzata nel contesto di una
subquery. Utilizza __name__ (il riferimento al documento) del documento corrente nell'ambito principale per determinare quale raccolta secondaria recuperare. Ad esempio, se il documento principale è /restaurants/pizza-place, subcollection("reviews") restituisce tutti i documenti della raccolta /restaurants/pizza-place/reviews.
Se il riferimento al documento è stato rinominato o non è possibile definire un
campo con __name__, scrivi manualmente il join come segue:
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"))
è ancora possibile, in quanto questa fase è fondamentalmente solo una semplificazione sintattica di questo formato di join più complesso.
Per i seguenti documenti:
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 });
La seguente query recupera ogni ristorante e riepiloga le relative recensioni in un
nuovo campo 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();
e produce i seguenti risultati:
{ 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 } },