Kesalahannya adalah karena ini bukan lagi array setelah Anda $unwind
dan karenanya tidak lagi menjadi argumen yang valid untuk $size
.
Anda tampaknya mencoba untuk "menggabungkan" beberapa jawaban yang ada tanpa memahami apa yang mereka lakukan. Yang Anda inginkan di sini adalah $filter
dan $size
db.collection.aggregate([
{ "$project": {
"total": {
"$size": {
"$filter": {
"input": "$Array",
"cond": { "$eq": [ "$$this.field1", "a" ] }
}
}
}
}}
])
Atau "temukan kembali roda" menggunakan $reduce
:
db.collection.aggregate([
{ "$project": {
"total": {
"$reduce": {
"input": "$Array",
"initialValue": 0,
"in": {
"$sum": [
"$$value",
{ "$cond": [{ "$eq": [ "$$this.field1", "a" ] }, 1, 0] }
}
}
}
}}
])
Atau untuk apa yang Anda coba lakukan dengan $unwind
, Anda sebenarnya $group
lagi untuk "menghitung" berapa banyak kecocokan yang ada:
db.collection.aggregate([
{ "$unwind": "$Array" },
{ "$match": { "Array.field1": "a" } },
{ "$group": {
"_id": "$_id",
"total": { "$sum": 1 }
}}
])
Dua bentuk pertama adalah "optimal" untuk lingkungan MongoDB modern. Formulir terakhir dengan $unwind
dan $group
adalah konstruksi "warisan" yang sebenarnya tidak diperlukan untuk jenis operasi ini sejak MongoDB 2.6, meskipun dengan beberapa operator yang sedikit berbeda.
Dalam dua yang pertama kami pada dasarnya membandingkan field1
nilai setiap elemen array saat masih berupa array. Keduanya $filter
dan $reduce
adalah operator modern yang dirancang untuk bekerja dengan susunan yang sudah ada. Perbandingan yang sama dilakukan pada masing-masing menggunakan agregasi $eq
operator yang mengembalikan nilai boolean berdasarkan apakah argumen yang diberikan "sama" atau tidak. Dalam hal ini pada setiap anggota array dengan nilai yang diharapkan dari "a"
.
Dalam kasus $filter
, array sebenarnya tetap utuh kecuali untuk elemen apa pun yang tidak memenuhi kondisi yang disediakan di "cond"
akan dihapus dari array. Karena kita masih memiliki "array" sebagai output, kita dapat menggunakan $ukuran
operator untuk mengukur jumlah elemen larik yang tersisa setelah kondisi filter tersebut diproses.
$reduce
di sisi lain bekerja melalui elemen array dan memasok ekspresi di setiap elemen dan nilai "akumulator" yang tersimpan, yang kami inisialisasi dengan "initialValue"
. Dalam hal ini $eq
yang sama
pengujian diterapkan dalam $cond
operator. Ini adalah "ternary" atau if/then/else
operator kondisional yang memungkinkan ekspresi yang diuji yang mengembalikan nilai boolean untuk mengembalikan then
nilai ketika true
atau else
nilai ketika false
.
Dalam ekspresi itu kami mengembalikan 1
atau 0
masing-masing dan berikan hasil keseluruhan dari penambahan nilai yang dikembalikan dan "akumulator" saat ini "$$value"
dengan $sum
operator untuk menambahkan ini bersama-sama.
Formulir terakhir menggunakan $unwind
pada larik. Apa yang sebenarnya dilakukan adalah mendekonstruksi anggota array untuk membuat "dokumen baru" untuk setiap anggota array dan bidang induk terkait dalam dokumen asli. Ini secara efektif "menyalin" dokumen utama untuk setiap anggota array.
Setelah Anda $unwind
struktur dokumen diubah menjadi bentuk yang "lebih datar". Inilah sebabnya mengapa Anda kemudian dapat melakukan $match
tahap pipa untuk menghapus dokumen yang tidak cocok.
Ini membawa kita ke $group
yang diterapkan untuk "mengumpulkan kembali" semua informasi yang terkait dengan kunci umum. Dalam hal ini adalah _id
bidang dokumen asli, yang tentu saja disalin ke setiap dokumen yang dihasilkan oleh $unwind
. Saat kita kembali ke "kunci umum" ini sebagai satu dokumen, kita dapat "menghitung" sisa "dokumen" yang diekstrak dari larik menggunakan $sum
akumulator.
Jika kami menginginkan "array" yang tersisa kembali, Anda dapat $dorong
dan bangun kembali array hanya dengan anggota yang tersisa:
{ "$group": {
"_id": "$_id",
"Array": { "$push": "$Array" },
"total": { "$sum": 1 }
}}
Tapi tentu saja daripada menggunakan $size
di tahap pipa lain, kita masih bisa "menghitung" seperti yang sudah kita lakukan dengan $sum