Kerangka kerja agregasi di MongoDB 3.4 dan yang lebih baru menawarkan $reduce
operator yang secara efisien menghitung total tanpa perlu pipa tambahan. Pertimbangkan untuk menggunakannya sebagai ekspresi untuk mengembalikan total peringkat dan mendapatkan jumlah peringkat menggunakan $size
. Bersama dengan $addFields
, rata-rata dapat dihitung dengan menggunakan operator aritmatika $divide
seperti pada rumus average = total ratings/number of ratings
:
db.collection.aggregate([
{
"$addFields": {
"rating_average": {
"$divide": [
{ // expression returns total
"$reduce": {
"input": "$ratings",
"initialValue": 0,
"in": { "$add": ["$$value", "$$this.rating"] }
}
},
{ // expression returns ratings count
"$cond": [
{ "$ne": [ { "$size": "$ratings" }, 0 ] },
{ "$size": "$ratings" },
1
]
}
]
}
}
}
])
Contoh Keluaran
{
"_id" : ObjectId("58ab48556da32ab5198623f4"),
"title" : "The Hobbit",
"ratings" : [
{
"title" : "best book ever",
"rating" : 5.0
},
{
"title" : "good book",
"rating" : 3.5
}
],
"rating_average" : 4.25
}
Dengan versi yang lebih lama, Anda harus terlebih dahulu menerapkan $unwind
operator pada ratings
bidang array terlebih dahulu sebagai langkah pipa agregasi awal Anda. Ini akan mendekonstruksi ratings
bidang array dari dokumen input ke output dokumen untuk setiap elemen. Setiap dokumen keluaran menggantikan array dengan nilai elemen.
Tahap pipa kedua adalah $group
operator yang mengelompokkan dokumen input dengan _id
dan title
ekspresi pengidentifikasi kunci dan menerapkan $avg
yang diinginkan ekspresi akumulator untuk setiap grup yang menghitung rata-rata. Ada operator akumulator lain $push
yang mempertahankan bidang larik peringkat asli dengan mengembalikan larik semua nilai yang dihasilkan dari penerapan ekspresi ke setiap dokumen dalam grup di atas.
Langkah pipa terakhir adalah $project
operator yang kemudian membentuk kembali setiap dokumen dalam aliran, seperti dengan menambahkan bidang baru ratings_average
.
Jadi, jika misalnya Anda memiliki contoh dokumen dalam koleksi Anda (seperti dari atas dan bawah):
db.collection.insert({
"title": "The Hobbit",
"ratings": [
{
"title": "best book ever",
"rating": 5
},
{
"title": "good book",
"rating": 3.5
}
]
})
Untuk menghitung rata-rata larik peringkat dan memproyeksikan nilai di bidang lain ratings_average
, Anda kemudian dapat menerapkan alur agregasi berikut:
db.collection.aggregate([
{
"$unwind": "$ratings"
},
{
"$group": {
"_id": {
"_id": "$_id",
"title": "$title"
},
"ratings":{
"$push": "$ratings"
},
"ratings_average": {
"$avg": "$ratings.rating"
}
}
},
{
"$project": {
"_id": 0,
"title": "$_id.title",
"ratings_average": 1,
"ratings": 1
}
}
])
Hasil :
/* 1 */
{
"result" : [
{
"ratings" : [
{
"title" : "best book ever",
"rating" : 5
},
{
"title" : "good book",
"rating" : 3.5
}
],
"ratings_average" : 4.25,
"title" : "The Hobbit"
}
],
"ok" : 1
}