Subkoleksi

Deskripsi

Tahap input subcollection(...) memudahkan untuk melakukan penggabungan induk-turunan menggunakan kolom __name__ bawaan.

Tahap tambahan dapat dirangkai ke tahap subcollection(...) untuk melakukan pemfilteran atau penggabungan pada dokumen bertingkat. Perhatikan bahwa referensi kolom yang digunakan pada tahap berikutnya mengacu pada dokumen dari koleksi bertingkat, bukan dokumen induk. Untuk merujuk ke kolom dalam cakupan induk, gunakan terlebih dahulu tahap let(...) untuk menentukan variabel, lalu rujuk variabel tersebut dalam cakupan lokal.

Contoh

Node.js

db.pipeline()
  .collection("/restaurants")
  .add_fields(subcollection("reviews")
    .aggregate(average("rating").as("avg_rating"))
    .toScalarExpression()
    .as("avg_rating"))

Perilaku

Tahap subcollection(...) harus digunakan dalam konteks subkueri. Fungsi ini menggunakan __name__ (referensi dokumen) dari dokumen saat ini dalam cakupan induk untuk menentukan subkoleksi yang akan diambil. Misalnya, jika dokumen induk adalah /restaurants/pizza-place, maka subcollection("reviews") akan menampilkan semua dokumen dari koleksi /restaurants/pizza-place/reviews.

Jika referensi dokumen telah diganti namanya, atau tidak mungkin menentukan kolom dengan __name__, maka tulis gabungan secara manual seperti:

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"))

masih memungkinkan karena pada dasarnya tahap ini hanyalah pintasan sintaksis atas format gabungan yang lebih kompleks ini.

Untuk dokumen berikut:

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 });

Kueri berikut mengambil setiap restoran dan merangkum ulasannya dalam kolom review_summary baru:

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();

dan menghasilkan hasil berikut:

{ 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 } },