하위 컬렉션

설명

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