تجمیع

توضیحات

مرحله aggregate(...) نتایج تجمیع شده (مثلاً count، sum) را از اسناد برگردانده شده توسط مرحله قبل محاسبه می‌کند.

به صورت اختیاری، وقتی یک عبارت گروه‌بندی ارائه می‌شود، اسناد را بر اساس عبارات ارائه شده گروه‌بندی می‌کند و سپس توابع انباشتگر را برای هر گروه اعمال می‌کند.

مثال‌ها

برای تجمیع بدون group-by، مرحله aggregate(...) یک یا چند عبارت تجمیع‌کننده با نام مستعار را می‌پذیرد:

نود جی اس

const cities = await db.pipeline()
  .collection("/cities")
  .aggregate(
      countAll().as("total"),
      average("population").as("avg_population")
  )
  .execute();

برای تجمیع‌هایی که قابلیت گروه‌بندی دارند، علاوه بر تجمیع‌کننده‌ها، گروه‌های دیگری نیز لازم است:

نود جی اس

const result = await db.pipeline()
  .collectionGroup('citites')
  .aggregate({
    accumulators: [
      countAll().as('cities'),
      field('population').sum().as('total_popoluation')
    ],
    groups: [field('location.state').as('state')]
  })
  .execute();

رفتار

تجمیع بدون گروه‌بندی

یک مجموعه cities با اسناد زیر ایجاد کنید:

نود جی اس

await db.collection('cities').doc('SF').set({name: 'San Francisco', state: 'CA', country: 'USA', population: 870000});
await db.collection('cities').doc('LA').set({name: 'Los Angeles', state: 'CA', country: 'USA', population: 3970000});
await db.collection('cities').doc('NY').set({name: 'New York', state: 'NY', country: 'USA', population: 8530000});
await db.collection('cities').doc('TOR').set({name: 'Toronto', state: null, country: 'Canada', population: 2930000});
await db.collection('cities').doc('MEX').set({name: 'Mexico City', state: null, country: 'Mexico', population: 9200000});

برای اطلاع از تعداد کل شهرها و میانگین جمعیت آنها:

نود جی اس

const cities = await db.pipeline()
  .collection("/cities")
  .aggregate(
      countAll().as("total"),
      average("population").as("avg_population")
  )
  .execute();

که تولید می‌کند:

{avg_population: 5100000, total: 5}

انجام تجمیع روی گروه‌ها

با ارائه آرگومان groups ، می‌توانید تجمیع‌ها را روی هر گروه مجزا انجام دهید.

برای مثال، برای یافتن شهری با بیشترین جمعیت در هر کشور و هر ایالت:

نود جی اس

const cities = await db.pipeline()
  .collection("/cities")
  .aggregate({
      accumulators: [
          countAll().as("number_of_cities"),
          maximum("population").as("max_population")
      ],
      groups: ["country", "state"]
  })
  .execute();

که می‌دهد:

{country: "USA", state: "CA", max_population: 3970000, number_of_cities: 2},
{country: "USA", state: "NY", max_population: 8530000, number_of_cities: 1},
{country: "Canada", state: null, max_population: 2930000, number_of_cities: 1},
{country: "Mexico", state: null,  max_population: 9200000, number_of_cities: 1}

عبارات پیچیده در گروه بندی

فراتر از گروه‌بندی بر اساس مقادیر فیلدها، مرحله aggregate(...) از گروه‌بندی بر اساس نتایج عبارات پیچیده پشتیبانی می‌کند. هر عبارتی که در مرحله select معتبر باشد، می‌تواند به عنوان کلید گروه‌بندی استفاده شود. این امر امکان گروه‌بندی انعطاف‌پذیر بر اساس مقادیر یا شرایط محاسبه‌شده را فراهم می‌کند.

برای مثال، برای گروه‌بندی بر اساس اینکه آیا فیلد ایالت تهی است یا خیر، و یافتن کل جمعیت در هر گروه:

نود جی اس

const cities = await db.pipeline()
  .collection("/cities")
  .aggregate({
      accumulators: [
         sum("population").as("total_population")
      ],
      groups: [equal(field("state"), null).as("state_is_null")]
  })
  .execute();

باز خواهد گشت:

{state_is_null: true, total_population: 12130000}
{state_is_null: false, total_population: 13370000}

رفتارهای تجمیع‌کننده

رفتار تجمیعی هر تابع پشتیبانی‌شده (مثلاً count ، sum ، avg ) را می‌توانید در صفحه اختصاصی توابع تجمیعی (Aggregate Functions) بیابید.

رفتارهای کلیدی گروه

هنگام گروه‌بندی اسناد، Firestore از معانی برابری برای تعیین اینکه آیا مقادیر متعلق به یک گروه هستند یا خیر، استفاده می‌کند.

این بدان معناست که مقادیر معادل، برای مثال مقادیر عددی معادل ریاضی، صرف نظر از نوع اصلی (عدد صحیح ۳۲ بیتی، عدد صحیح ۶۴ بیتی، اعداد ممیز شناور، decimal128 و غیره)، همگی با هم گروه‌بندی می‌شوند.

به عنوان مثال، در یک مجموعه numerics با اسناد مختلف که حاوی مقادیر foo به ترتیب عدد صحیح ۳۲ بیتی 1 ، عدد صحیح ۶۴ بیتی 1L و عدد اعشاری 1.0 هستند، همه آنها در یک گروه جمع می‌شوند. اجرای یک گروه‌بندی شمارشی بر اساس foo نتیجه زیر را برمی‌گرداند:

{foo: 1.0, count: 3}

در چنین مواردی که مقادیر معادل متفاوتی در مجموعه داده‌ها وجود دارد، مقدار خروجی گروه می‌تواند هر یک از این مقادیر معادل باشد. در این مثال، foo می‌تواند 1 ، 1L یا 1.0 باشد.

حتی اگر قطعی به نظر برسد، نباید سعی کنید به رفتار یک مقدار خاص که انتخاب می‌شود تکیه کنید.

میزان استفاده از حافظه

نحوه اجرای تجمیع به شاخص‌های موجود بستگی دارد. وقتی شاخص مناسبی توسط بهینه‌ساز پرس‌وجو انتخاب نشده باشد، تجمیع باید تمام گروه‌ها را در حافظه بافر کند.

در صورت داشتن تعداد بسیار زیادی گروه، یا بزرگ بودن هر گروه (مثلاً گروه‌بندی بر اساس مقادیر بسیار بزرگ)، این مرحله ممکن است با کمبود حافظه مواجه شود.

در چنین مواردی، باید فیلترهایی را برای محدود کردن تجمیع مجموعه داده‌ها، گروه‌بندی بر اساس فیلدهای کوچک‌تر/کمتر، یا ایجاد شاخص‌ها طبق توصیه برای جلوگیری از استفاده زیاد از حافظه، اعمال کنید. Query Explain اطلاعاتی در مورد طرح اجرای واقعی پرس‌وجو و پروفایل‌بندی داده‌ها برای کمک به اشکال‌زدایی ارائه می‌دهد.