Tidak peduli bagaimana Anda menyusun keseluruhan dokumen Anda, pada dasarnya ada dua hal yang Anda butuhkan. Itu pada dasarnya adalah properti untuk "hitungan" dan "daftar" dari mereka yang telah memposting "suka" mereka untuk memastikan tidak ada duplikat yang dikirimkan. Berikut struktur dasarnya:
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3")
"photo": "imagename.png",
"likeCount": 0
"likes": []
}
Apapun masalahnya, ada "_id" unik untuk "posting foto" Anda dan informasi apa pun yang Anda inginkan, tetapi kemudian bidang lain seperti yang disebutkan. Properti "suka" di sini adalah larik, dan itu akan menyimpan nilai unik "_id" dari objek "pengguna" di sistem Anda. Jadi setiap "pengguna" memiliki pengidentifikasi unik mereka sendiri di suatu tempat, baik di penyimpanan lokal atau OpenId atau sesuatu, tetapi pengidentifikasi unik. Saya akan tetap menggunakan ObjectId
misalnya.
Ketika seseorang mengirimkan "suka" ke sebuah pos, Anda ingin mengeluarkan pernyataan pembaruan berikut:
db.photos.update(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
"likes": { "$ne": ObjectId("54bb2244a3a0f26f885be2a4") }
},
{
"$inc": { "likeCount": 1 },
"$push": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
}
)
Sekarang $inc
operasi di sana akan meningkatkan nilai "likeCount" dengan angka yang ditentukan, jadi bertambah 1. The $push
operasi menambahkan pengidentifikasi unik untuk pengguna ke larik dalam dokumen untuk referensi di masa mendatang.
Hal penting utama di sini adalah menyimpan catatan pengguna yang memberikan suara dan apa yang terjadi di bagian "permintaan" dari pernyataan tersebut. Selain memilih dokumen yang akan diperbarui dengan "_id" uniknya sendiri, hal penting lainnya adalah memeriksa larik "suka" untuk memastikan pengguna voting saat ini belum ada di sana.
Hal yang sama berlaku untuk kasus terbalik atau "menghapus" "suka":
db.photos.update(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
"likes": ObjectId("54bb2244a3a0f26f885be2a4")
},
{
"$inc": { "likeCount": -1 },
"$pull": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
}
)
Hal utama yang penting di sini adalah kondisi kueri yang digunakan untuk memastikan bahwa tidak ada dokumen yang disentuh jika semua kondisi tidak terpenuhi. Jadi hitungan tidak bertambah jika pengguna telah memilih atau berkurang jika suara mereka tidak benar-benar hadir lagi pada saat pembaruan.
Tentu saja tidak praktis untuk membaca larik dengan beberapa ratus entri dalam dokumen di bagian lain aplikasi Anda. Tetapi MongoDB juga memiliki cara yang sangat standar untuk menanganinya:
db.photos.find(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
},
{
"photo": 1
"likeCount": 1,
"likes": {
"$elemMatch": { "$eq": ObjectId("54bb2244a3a0f26f885be2a4") }
}
}
)
Penggunaan $elemMatch
. ini dalam proyeksi hanya akan mengembalikan pengguna saat ini jika mereka ada atau hanya array kosong di mana mereka tidak ada. Hal ini memungkinkan logika aplikasi Anda lainnya untuk mengetahui apakah pengguna saat ini telah memberikan suara atau belum.
Itu adalah teknik dasar dan mungkin bekerja untuk Anda apa adanya, tetapi Anda harus menyadari bahwa array yang disematkan tidak boleh diperpanjang tanpa batas, dan ada juga batasan 16MB pada dokumen BSON. Jadi konsepnya masuk akal, tetapi tidak dapat digunakan sendiri jika Anda mengharapkan 1000 "suara suka" pada konten Anda. Ada konsep yang dikenal sebagai "bucketing" yang dibahas secara rinci dalam contoh ini untuk desain Skema Hibrida yang memungkinkan satu solusi untuk menyimpan volume "suka" yang tinggi. Anda dapat melihatnya untuk digunakan bersama dengan konsep dasar di sini sebagai cara untuk melakukannya pada volume.