サブコレクション

説明

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