Deskripsi
Tahap aggregate menghitung hasil gabungan (misalnya, jumlah, total) dari
dokumen yang ditampilkan oleh tahap sebelumnya.
Saat ekspresi pengelompokan diberikan, tahap ini secara opsional dapat mengelompokkan dokumen berdasarkan ekspresi yang diberikan, lalu menerapkan fungsi akumulator ke setiap kelompok.
Sintaksis
Untuk agregasi tanpa pengelompokan, tahap aggregate akan menggunakan satu atau beberapa
ekspresi agregator yang diberi alias:
Node.js
const cities = await db.pipeline()
.collection("/cities")
.aggregate(
countAll().as("total"),
average("population").as("avg_population")
)
.execute();
Untuk agregasi dengan pengelompokan, tahap ini akan menggunakan kelompok tambahan selain agregator:
Node.js
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();
Perilaku
Agregasi Tanpa Pengelompokan
Buat koleksi cities dengan dokumen berikut:
Node.js
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});
Untuk mengetahui jumlah total kota dan rata-rata populasinya:
Node.js
const cities = await db.pipeline()
.collection("/cities")
.aggregate(
countAll().as("total"),
average("population").as("avg_population")
)
.execute();
yang menghasilkan:
{avg_population: 5100000, total: 5}
Melakukan Agregasi pada Kelompok
Dengan memberikan argumen groups, Anda dapat melakukan agregasi pada setiap kelompok yang berbeda.
Misalnya, untuk menemukan kota dengan populasi terbesar di setiap negara dan negara bagian:
Node.js
const cities = await db.pipeline()
.collection("/cities")
.aggregate({
accumulators: [
countAll().as("number_of_cities"),
maximum("population").as("max_population")
],
groups: ["country", "state"]
})
.execute();
yang memberikan:
{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}
Ekspresi Kompleks pada Pengelompokan
Selain pengelompokan hanya menurut nilai kolom, tahap aggregate juga mendukung
pengelompokan menurut hasil ekspresi kompleks. Ekspresi apa pun yang valid dalam tahap
select dapat digunakan sebagai kunci pengelompokan. Hal ini memungkinkan pengelompokan
yang fleksibel berdasarkan kondisi atau nilai yang dihitung.
Misalnya, untuk mengelompokkan menurut ada atau tidaknya nilai null pada kolom negara bagian, dan mengetahui total populasi di setiap kelompok:
Node.js
const cities = await db.pipeline()
.collection("/cities")
.aggregate({
accumulators: [
sum("population").as("total_population")
],
groups: [equal(field("state"), null).as("state_is_null")]
})
.execute();
akan menampilkan:
{state_is_null: true, total_population: 12130000}
{state_is_null: false, total_population: 13370000}
Perilaku Agregator
Perilaku agregasi dari setiap fungsi yang didukung (misalnya, count, sum, avg) dapat
ditemukan di halaman khusus untuk
Fungsi Agregat.
Perilaku Kunci Kelompok
Saat mengelompokkan dokumen, Firestore menggunakan semantik kesetaraan untuk menentukan apakah nilai termasuk dalam kelompok yang sama.
Artinya, nilai yang setara, misalnya nilai numerik yang secara matematis setara, terlepas dari jenis aslinya (bilangan bulat 32-bit, bilangan bulat 64-bit, bilangan floating point, decimal128, dll.), semuanya akan dikelompokkan bersama.
Sebagai contoh, dalam koleksi numerics dengan berbagai dokumen yang masing-masing berisi nilai foo
bilangan bulat 32-bit 1, bilangan bulat 64-bit 1L, dan bilangan floating point 1.0,
semuanya akan dikumpulkan ke dalam kelompok yang sama. Jika Anda menjalankan penghitungan
pengelompokan menurut foo, hasilnya akan berupa:
{foo: 1.0, count: 3}
Jika ada nilai setara yang berbeda dalam set data,
nilai output kelompok dapat berupa salah satu dari nilai setara tersebut.
Dalam contoh ini, foo dapat berupa 1, 1L, atau 1.0.
Meskipun tampak deterministik, Anda tidak boleh mencoba mengandalkan perilaku satu nilai spesifik yang dipilih.
Pemakaian Memori
Cara eksekusi agregasi bergantung pada indeks yang tersedia. Jika tidak ada indeks yang sesuai yang dipilih oleh pengoptimal kueri, agregat harus melakukan buffering untuk semua kelompok dalam memori.
Jika ada kelompok dalam jumlah besar, atau setiap kelompok bernilai sangat besar (misalnya, pengelompokan menurut nilai yang sangat besar), tahap ini bisa saja kehabisan memori.
Dalam kasus seperti ini, sebaiknya terapkan filter untuk membatasi set data yang akan diagregasi, lakukan pengelompokan di kolom yang lebih kecil/sedikit, atau buat indeks sesuai rekomendasi untuk menghindari penggunaan memori yang besar. Query Explain akan memberikan informasi tentang rencana eksekusi kueri yang sebenarnya dan data profiling untuk membantu proses debug.