Mô tả
Giai đoạn đầu vào subcollection(...) giúp bạn dễ dàng thực hiện các phép kết hợp giữa phần tử mẹ và phần tử con bằng cách sử dụng trường __name__ tích hợp.
Bạn có thể liên kết các giai đoạn bổ sung vào giai đoạn subcollection(...) để lọc hoặc tổng hợp các tài liệu lồng nhau. Xin lưu ý rằng mọi tham chiếu đến trường được sử dụng trong các giai đoạn tiếp theo đều tham chiếu đế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 mẹ,
trước tiên, hãy sử 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 bối cảnh của một truy vấn phụ. Giai đoạn này sử dụng __name__ (tham chiếu đến tài liệu) của tài liệu hiện tại trong phạm vi mẹ để xác định bộ sưu 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 trong bộ sưu tập
/restaurants/pizza-place/reviews.
Nếu bạn đã đổi tên tham chiếu đến tài liệu hoặc không thể xác định một trường bằng __name__, thì bạn vẫn có thể viết phép 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ề cơ bản, giai đoạn này chỉ là cú pháp dễ hiểu hơn so với định dạng kết hợp phức tạp 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 sẽ 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à tạo 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 } },