MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

Komentar permintaan MongoDB bersama dengan informasi pengguna

Masalahnya

Seperti yang ditulis sebelumnya , ada beberapa masalah saat penyematan berlebihan:

Masalah 1:Batas ukuran BSON

Pada saat penulisan ini, Dokumen BSON dibatasi hingga 16MB . Jika batas itu tercapai, MongoDB akan mengeluarkan pengecualian dan Anda tidak dapat menambahkan lebih banyak komentar dan dalam skenario terburuk bahkan tidak mengubah nama (pengguna) atau gambar jika perubahan tersebut akan meningkatkan ukuran dokumen.

Masalah 2:Batasan dan performa kueri

Tidak mudah untuk mengkueri atau mengurutkan larik komentar dalam kondisi tertentu. Beberapa hal memerlukan agregasi yang agak mahal, yang lain pernyataan yang agak rumit.

Sementara orang bisa berargumen bahwa begitu pertanyaannya ada, ini bukan masalah besar, saya mohon berbeda. Pertama, semakin rumit kueri, semakin sulit untuk dioptimalkan, baik untuk pengembang maupun pengoptimal kueri MongoDB. Saya mendapatkan hasil terbaik dengan menyederhanakan model data dan kueri, mempercepat respons hingga faktor 100 dalam satu contoh.

Saat penskalaan, sumber daya yang diperlukan untuk kueri yang rumit dan/atau mahal bahkan mungkin berjumlah keseluruhan mesin jika dibandingkan dengan model data yang lebih sederhana dan kueri yang sesuai.

Masalah 3:Pemeliharaan

Last but not least, Anda mungkin mengalami masalah dalam mempertahankan kode Anda. Sebagai aturan praktis

Dalam konteks ini, "mahal" mengacu pada uang (untuk proyek profesional) dan waktu (untuk proyek hobi).

(Saya!) Solusi

Ini cukup mudah:sederhanakan model data Anda. Akibatnya, kueri Anda akan menjadi tidak terlalu rumit dan (semoga) lebih cepat.

Langkah 1:Identifikasi kasus penggunaan Anda

Itu akan menjadi tebakan liar bagi saya, tetapi yang penting di sini adalah menunjukkan metode umumnya. Saya akan mendefinisikan kasus penggunaan Anda sebagai berikut:

  1. Untuk postingan tertentu, pengguna harus dapat berkomentar
  2. Untuk postingan tertentu, tunjukkan penulis dan komentarnya, bersama dengan pemberi komentar dan nama pengguna penulis serta fotonya
  3. Untuk pengguna tertentu, seharusnya dapat dengan mudah mengubah nama, nama pengguna, dan gambar

Langkah 2:Modelkan data Anda sesuai dengan itu

Pengguna

Pertama-tama, kami memiliki model pengguna langsung

{
  _id: new ObjectId(),
  name: "Joe Average",
  username: "HotGrrrl96",
  picture: "some_link"
}

Tidak ada yang baru di sini, ditambahkan hanya untuk kelengkapan.

Pos

{
  _id: new ObjectId()
  title: "A post",
  content: " Interesting stuff",
  picture: "some_link",
  created: new ISODate(),
  author: {
    username: "HotGrrrl96",
    picture: "some_link"
  }
}

Dan itu saja untuk sebuah posting. Ada dua hal yang perlu diperhatikan di sini:pertama, kami menyimpan data penulis yang segera kami perlukan saat menampilkan kiriman, karena ini menyelamatkan kami dari kueri untuk kasus penggunaan yang sangat umum, jika tidak ada di mana-mana. Mengapa kita tidak menyimpan data komentar dan komentator secara berurutan? Karena batas ukuran 16 MB , kami mencoba untuk mencegah penyimpanan referensi dalam satu dokumen. Sebaliknya, kami menyimpan referensi dalam dokumen komentar:

Komentar

{
  _id: new ObjectId(),
  post: someObjectId,
  created: new ISODate(),
  commenter: {
    username: "FooBar",
    picture: "some_link"
  },
  comment: "Awesome!"
}

Sama seperti postingan, kami memiliki semua data yang diperlukan untuk menampilkan postingan.

Kueri

Apa yang telah kami capai sekarang adalah kami menghindari batas ukuran BSON dan kami tidak perlu merujuk ke data pengguna untuk dapat menampilkan posting dan komentar, yang seharusnya menghemat banyak pertanyaan. Tapi mari kembali ke kasus penggunaan dan beberapa pertanyaan lagi

Menambahkan komentar

Itu benar-benar mudah sekarang.

Mendapatkan semua atau sebagian komentar untuk postingan tertentu

Untuk semua komentar

db.comments.find({post:objectIdOfPost})

Untuk 3 komentar terakhir

db.comments.find({post:objectIdOfPost}).sort({created:-1}).limit(3)

Jadi untuk menampilkan posting dan semua (atau sebagian) komentarnya termasuk nama pengguna dan gambar, kami berada di dua pertanyaan. Lebih dari yang Anda butuhkan sebelumnya, tetapi kami menghindari batas ukuran dan pada dasarnya Anda dapat memiliki jumlah komentar yang tidak terbatas untuk setiap posting. Tapi mari kita lakukan sesuatu yang nyata

Mendapatkan 5 postingan terbaru dan 3 komentar terbaru

Ini adalah proses dua langkah. Namun, dengan pengindeksan yang tepat (akan kembali lagi nanti) ini masih harus cepat (dan karenanya menghemat sumber daya):

var posts = db.posts.find().sort({created:-1}).limit(5)
posts.forEach(
  function(post) {
    doSomethingWith(post);
    var comments = db.comments.find({"post":post._id}).sort("created":-1).limit(3);
    doSomethingElseWith(comments);
  }
)

Dapatkan semua posting dari pengguna tertentu yang diurutkan dari yang terbaru ke terlama dan komentar mereka

var posts = db.posts.find({"author.username": "HotGrrrl96"},{_id:1}).sort({"created":-1});
var postIds = [];
posts.forEach(
  function(post){
    postIds.push(post._id);
  }
)
var comments = db.comments.find({post: {$in: postIds}}).sort({post:1, created:-1});

Perhatikan bahwa kami hanya memiliki dua pertanyaan di sini. Meskipun Anda perlu "secara manual" membuat hubungan antara postingan dan komentar masing-masing, itu seharusnya cukup mudah.

Ubah nama pengguna

Ini mungkin adalah kasus penggunaan yang jarang dieksekusi. Namun, tidak terlalu rumit dengan model data tersebut

Pertama, kita ubah dokumen pengguna

db.users.update(
  { username: "HotGrrrl96"},
  {
    $set: { username: "Joe Cool"},
    $push: {oldUsernames: "HotGrrrl96" }
  },
  {
    writeConcern: {w: "majority"}
  }
);

Kami mendorong nama pengguna lama ke array yang sesuai. Ini adalah tindakan pengamanan jika terjadi kesalahan dengan operasi berikut. Selain itu, kami menyetel perhatian penulisan ke tingkat yang agak tinggi untuk memastikan data tahan lama.

db.posts.update(
  { "author.username": "HotGrrrl96"},
  { $set:{ "author.username": "Joe Cool"} },
  {
    multi:true,
    writeConcern: {w:"majority"}
  }
)

Tidak ada yang istimewa di sini. Pernyataan pembaruan untuk komentar terlihat hampir sama. Meskipun kueri tersebut membutuhkan waktu, kueri tersebut jarang dieksekusi.

Indeks

Sebagai aturan praktis, dapat dikatakan bahwa MongoDB hanya dapat menggunakan satu indeks per kueri. Meskipun ini tidak sepenuhnya benar karena ada perpotongan indeks, ini mudah untuk ditangani. Hal lain adalah bahwa bidang individu dalam indeks gabungan dapat digunakan secara independen. Jadi pendekatan yang mudah untuk pengoptimalan indeks adalah menemukan kueri dengan bidang yang paling banyak digunakan dalam operasi yang menggunakan indeks dan membuat indeks gabungannya. Perhatikan bahwa urutan kemunculan dalam kueri itu penting. Jadi, mari kita lanjutkan.

Pos

db.posts.createIndex({"author.username":1,"created":-1})

Komentar

db.comments.createIndex({"post":1, "created":-1})

Kesimpulan

Dokumen yang disematkan sepenuhnya per posting diakui adalah cara tercepat untuk memuatnya dan komentarnya. Namun, skalanya tidak baik dan karena sifat kueri kompleks yang mungkin diperlukan untuk menanganinya, keunggulan kinerja ini dapat dimanfaatkan atau bahkan dihilangkan.

Dengan solusi di atas, Anda memperdagangkan beberapa kecepatan (jika!) dengan skalabilitas yang pada dasarnya tidak terbatas dan cara yang jauh lebih mudah untuk menangani data.

Ht.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Bagaimana saya harus menyusun aplikasi node/express/mongodb saya?

  2. Kunci Asing Validasi Mongoose (ref)

  3. Lewati variabel ke pembaruan mongo?

  4. Apa perbedaan antara findAndModify dan pembaruan di MongoDB?

  5. Bagaimana cara saya menanyakan objek yang direferensikan di MongoDB?