子集合

说明

借助 subcollection(...) 输入阶段,您可以轻松使用内置的 __name__ 字段执行父子联接。

其他阶段可以链接到 subcollection(...) 阶段,以对嵌套文档执行过滤或聚合操作。请注意,后续阶段中使用的任何字段引用都指向嵌套集合中的文档,而不是父文档。如需引用父范围中的字段,请先使用 let 阶段定义变量,然后在本地范围中引用这些变量。

示例

Node.js

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

行为

subcollection(...) 阶段必须在子流水线的上下文中使用。它使用父范围中当前文档的 __name__(文档引用)来确定要提取哪个子集合。例如,如果父文档为 /restaurants/pizza-place,则 subcollection("reviews") 会返回 /restaurants/pizza-place/reviews 集合中的所有文档。

如果文档引用已重命名,或者无法使用 __name__ 定义字段,则手动编写联接,如下所示:

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

仍然可以实现,因为从根本上讲,此阶段只是对这种更复杂的联接格式的语法糖。

对于以下文档:

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

以下查询会检索每家餐厅,并在新的 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();

并生成以下结果:

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