Bộ sưu tập con

Mô tả

Giai đoạn đầu vào subcollection(...) giúp bạn dễ dàng thực hiện các thao tác kết hợp cha-con bằng cách sử dụng trường __name__ tích hợp sẵn.

Bạn có thể thêm các giai đoạn khác vào giai đoạn subcollection(...) để thực hiện việc lọc hoặc tổng hợp trên các tài liệu lồng nhau. Xin lưu ý rằng mọi giá trị tham chiếu trường được dùng trong các giai đoạn tiếp theo đều đề cập đến các tài liệu trong bộ sưu tập lồng nhau, chứ không phải tài liệu mẹ. Để tham chiếu đến các trường trong phạm vi gốc, trước tiên, hãy dùng giai đoạn let(...) để xác định các biến, sau đó tham chiếu đến các biến đó trong phạm vi cục bộ.

Ví dụ

Node.js

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

Hành vi

Bạn phải sử dụng giai đoạn subcollection(...) trong ngữ cảnh của một truy vấn phụ. Thao tác này sử dụng __name__ (tham chiếu tài liệu) của tài liệu hiện tại trong phạm vi gốc để xác định phân tập con cần tìm nạp. Ví dụ: nếu tài liệu mẹ là /restaurants/pizza-place, thì subcollection("reviews") sẽ trả về tất cả tài liệu từ bộ sưu tập /restaurants/pizza-place/reviews.

Nếu tên tham chiếu tài liệu đã được đổi hoặc không thể xác định một trường bằng __name__, hãy viết câu lệnh kết hợp theo cách thủ công như sau:

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

vẫn có thể vì về cơ bản, giai đoạn này chỉ là cú pháp dễ hiểu so với định dạng kết hợp phức tạp hơn này.

Đối với các tài liệu sau:

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

Truy vấn sau đây truy xuất từng nhà hàng và tóm tắt các bài đánh giá của nhà hàng đó trong một trường review_summary mới:

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

và cho ra kết quả sau:

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