Ana içeriğe geç

Blog Uygulamaları için MongoDB Veri Modellemesi Rehberi

Bir içerik yönetim sistemi (CMS) veya blog uygulaması tasarlarken, iç içe geçmiş belgeleri de içeren bazı veri modelleme olasılıklarını öğrenin.
· 7 dk. oku

Yapay Zeka ile Keşfedin

Kendi içerik yönetim sisteminizi (CMS), bazen blog olarak da adlandırılır, oluşturmak mı istiyorsunuz? Bu, ister ilişkisel veritabanı yönetim sistemi (RDBMS) ister NoSQL veritabanı olsun, bir veritabanını kullanmayı öğrenirken klasik bir örnektir; çünkü potansiyel olarak büyük miktarda veriyi ve o verilerdeki ilişkileri keşfetmenizi sağlar. Bir blog uygulaması örneği, diğer veri modelleme ihtiyaçları için de iyi bir şekilde uyarlanabilir.

Bu yazıda, MongoDB’de NoSQL belgelerinizi tasarlarken yapılması ve yapılmaması gereken bazı noktaları inceleyeceğiz. Ancak, aslında bir blog uygulaması geliştirmeyeceğiz; yalnızca konuyu veri perspektifinden ele alacağız.

Bir Blog Uygulamasının Bileşenleri

Bir blog için belge modeli tasarlamaya çalışmadan önce, geri adım atıp veriyle ilişkili olabilecek her bileşeni düşünmek iyi bir fikirdir.

Tipik bir blog şu özelliklere sahip olabilir:

  • Birden çok kullanıcı veya yazar
  • Her bir yazar için birden çok blog yazısı
  • Her bir blog yazısı için birden çok yorum

Elbette, bu özellik listesi blogunuzdaki iş ihtiyaçlarınıza bağlı olarak daha uzun ve karmaşık hale gelebilir. Basit tutmak adına, verilerimizi yukarıdakilere göre modelleyeceğiz.

Yapabileceğiniz Ama Yapmamanız Gerekenler

Yukarıdaki özelliklere bakarken ilk aklınıza gelen, her maddeyi kendi belgesi olarak ele almak olabilir. Bu, Postgres gibi ilişkisel bir veritabanında kullanacağınız tipik yaklaşımdır. MongoDB’de ise aşağıdakine benzer görünebilir:

{
	"_id": "author-1",
	"name": "Nic Raboy",
	"description": "I'm some dude named Nic."
}

Yukarıdaki, bir yazarın oldukça sadeleştirilmiş bir temsilidir. Elbette email gibi başka alanlar da olabilir, ancak burada gerçekten önemli olan bu değil.

Ardından, blog yazıları için de aşağıdakine benzer bir şeyimiz olabilir:

{
	"_id": "blog-1",
	"author_id": "author-1",
	"title": "MongoDB is Awesome!",
	"content": "This is some blog content..."
}

Tıpkı önceki gibi, blog belgesinde de tags gibi başka alanlar olabilir. Buradaki önemli nokta, iki belge arasında bir id referansının bulunmasıdır. Ancak buna birazdan döneceğiz.

Bu senaryodaki son belge modeli ise yorumlarla ilgili olacaktır:

{
	"_id": "comment-1",
	"blog_id": "blog-1",
	"username": "Anonymous User",
	"content": "Hey great article, it really helped a lot!"
}

Yine bu senaryoda, yorum belgesi ile blog belgesi arasında bir id değerine dayalı bir referans ilişkisi vardır. Bu, ilişkisel bir veritabanında oldukça yaygındır ve dürüst olmak gerekirse MongoDB’de de işe yarar. Ancak bu, size en iyi MongoDB deneyimini sunmayacaktır.

Bunu MongoDB’de yapmak istememenizin nedenlerinden biri performanstır.

Bu üç belgeyi birleştirmek için bir toplulaştırma ardışık düzeni içinde $lookup işlemi kullanmanız gerekir. Bu $lookup işlemleri ucuz değildir ve veritabanınız ölçeklendikçe performansınızı olumsuz etkileyebilir; özellikle de ardışık düzeninizde birden fazla $lookup olduğunda.

MongoDB’de işi halletmenin daha iyi yolları vardır.

Veri Modellemesine Daha İyi, MongoDB Dostu Bir Yaklaşım

MongoDB’nin ilk kurallarından biri, birlikte erişilen verilerin birlikte depolanmasıdır. Her özelliği ayrı bir belgeye veya koleksiyona koymak, kullanıcının gördüğü veriler için artık tek bir getirme işlemi yapmadığımızdan bu kuralı bozar.

Soruna başka bir açıdan bakalım ve blogumuz için belgeleri şu şekilde modelleyelim:

{
	"_id": "author-1",
	"name": "Nic Raboy",
	"description": "I'm some dude named Nic.",
	"posts": [
		{
			"title": "MongoDB is Awesome!",
			"content": "This is some blog content...",
			"comments": [
				{
					"username": "Anonymous User",
					"content": "Hey great article, it really helped a lot!"
				}
			]
		}
	]
}

Güzel, yukarıdaki modelde MongoDB’nin temel kurallarından biri karşılanıyor. Tüm blog yazılarını ve tüm yorumları, yazarla birlikte iç içe yerleştirme kullanarak tek bir belgede tutuyoruz.

İşe yarayabilse de, blog uygulamanızın belgelerini bu şekilde modellemek muhtemelen iyi bir fikir değildir.

MongoDB’nin belge boyutu sınırları vardır ve bu belgelerde sınırsız diziler (array) olduğunda bu sınırları aşma riskiyle karşılaşırsınız. Ayrıca diziler büyüdükçe performans sorunları yaşayabilirsiniz. Bu durumda, sınırsız sayıda blog yazımız ve blog başına sınırsız sayıda yorumumuz olabilir. Bir noktada işler karışacaktır.

Bu örnekte daha iyi çalışabilecek şey, iki stratejinin karışık bir şekilde kullanılmasıdır.

Unutmayın, yazarlar, blog yazıları ve yorumlar onlarla ilişkili herhangi sayıda alana sahip olabilir. Bu örnekte, minimumda tuttuk. Bunu göz önünde bulundurarak, en sık erişilen verinin bizzat blog olacağını biliyoruz. Yeni tasarıma bakın:

{
	"_id": "blog-1",
	"author": {
		"_id": "author-1",
		"name": "Nic Raboy",
	},
	"title": "MongoDB is Awesome!",
	"content": "This is some blog content...",
	"comments": [
		{
			"username": "Anonymous User",
			"content": "Hey great article, it really helped a lot!"
		}
	]
}

Bu örnekte sahip olduğumuz ikinci belge ise hâlâ yazar bilgileri için orijinal belgedir:

{
	"_id": "author-1",
	"name": "Nic Raboy",
	"description": "I'm some dude named Nic."
}

Bir blog yazısı görüntülenirken yazar bilgilerinin bir kısmının dahil edilmesi gerektiğini biliyoruz, ancak tüm bilgilere mutlaka ihtiyacımız yok. Gerekli yazar bilgilerini _id ile birlikte blog yazısının içine gömebiliriz; kullanıcı yazar hakkında daha fazlasını öğrenmek isterse, uygulamanızda daha derine inebilir. $lookup işlemi her seferinde gerçekleşmez; bu da performansı iyileştirir.

Şimdi de, bir blog yazısı için potansiyel olarak sınırsız sayıda olabilecek yorumların şu anda bir dizi olarak ekli olması sorunuyla karşı karşıyayız.

Bunu ele almak için birkaç yaklaşım vardır ve nihayetinde size kalmıştır:

  • Saf yaklaşımı seçip onları bir dizi olarak tutabilirsiniz; muhtemelen iyi bir fikir değildir.
  • Yorumları geri alıp, her yorumun blog yazısına referans id’si olan orijinal tasarıma taşıyabilir ve onları dahil etmek için $lookup işlemleri kullanabilirsiniz.
  • Arşivleme stratejisi kullanabilirsiniz: Blog yazısı içinde sabit sayıda yorumu bir dizi olarak tutarken, her biri için ayrı bir yorum belgesi de oluşturursunuz; böylece yalnızca gerektiğinde ekstra yorumları sorgularsınız.
  • Kova (bucket) desenini keşfedebilirsiniz: Yorumları, belge başına yaklaşık 100 yorumdan oluşan “kovalar” halinde gruplandırır, her seferinde ihtiyaç duyduğunuz kadar yorum kovasını sorgularsınız. Kovalamak, belge boyutu sınırından kaçınır ve sayfalamaya da yardımcı olur. Bu yaklaşımda blog_id üzerinde indeks oluşturarak belirli bir blog yazısının yorumlarını hızlıca getirmek için performansı artırabilirsiniz. İndeksleme hakkında daha fazla bilgiye MongoDB belgelerinde ulaşabilirsiniz.
  • Karıştır, eşleştir ve daha fazlası...

Kova deseninde, yorum belgeleriniz aşağıdakine benzer görünebilir:

{
	"_id": "comment-bucket-1",
	"blog_id": "blog-1",
	"comments": [
		{
			"username": "Anonymous User",
			"content": "Hey great article, it really helped a lot!"
		},
		// More comments here...
	],
	"comment_count": 57
}

Bu senaryoda, yeni yorumlar oluşturuldukça, dolu olmayan bir kovayı sorgularsınız. Yeni yorumu diziye eklersiniz ve sayacı artırırsınız. Bu strateji kovaları korumak için uygulama düzeyinde daha fazla mantık gerektirse de daha iyi performans sağlar. Blogunuzda sonsuz kaydırma mekanizması varsa daha da iyi, çünkü kovaları kullanarak sayfalamayı daha iyi yapabilirsiniz.

Bu özel makalenin kapsamı dışında olsa da, yeni bir yorum eklemek için neler gerektiğine dair bir fikir edinmek isterseniz, yorum kovaları koleksiyonunu (aşağıdaki örnek sorguya bakın) hem blog_id ile eşleşen hem de comment_count seçtiğiniz değerden küçük olan kovalar için filtrelersiniz.

Eşleşme için, güncelleme ölçütlerinizde $push operatörünü ve yorum sayacınızın değerini artırmak için $inc operatörünü kullanırsınız. Tüm bunlar tek bir işlemde yapılabilir ve upsert bayrağını kullanırsanız, ölçütlerinize uyan bir yorum kovası zaten yoksa yeni bir tane oluşturabilirsiniz.

Güncelleme sorgusu örneği: 

db.commentBuckets.updateOne(
  { blog_id: "blog-1", comment_count: { $lt: 100 } },
  { $push: { comments: newComment }, $inc: { comment_count: 1 } },
  { upsert: true }
)

Sonuç

Blogunuzla ilgili her şeyi tek bir iç içe geçmiş belgede saklamanız gerektiğini söylemek harika olurdu, ancak muhtemelen iyi bir fikir değildir. Tıpkı ilişkisel bir veritabanıyla iyi çalışan ancak MongoDB gibi bir belge veritabanı için pek de uygun olmayan bir veri modelini uygulamanın iyi bir fikir olmayacağı gibi.

MongoDB ile, mümkün olduğunca az referanslı ilişki kullanmak en iyi performansı elde etmenizi sağlar.

Ölçeklenirken şunları aklınızda bulundurun:

  • Yoğun yorum bekliyorsanız, kova desenini veya blog belgesi içinde kısmi gömme ile birlikte bir kombinasyonunu düşünün.
  • Sayfalama ihtiyaçlarınız neler?
  • Uygulamanızda nasıl sorgulamayı planladığınıza göre koleksiyonlarınızı indeksleyin.

Yinelemek gerekirse, blog verilerini ön yüzde nasıl sunacağınızı düşünün. Gerçekten istekte tüm yazar bilgilerine ihtiyaç var mı, yoksa bir kısmı yeterli mi? Blog yazınızla birlikte gerçekten bir milyon yorumu yüklemek istiyor musunuz, yoksa küçük bir kısmını yüklemek yeterli mi? Gerçekten düşündüğünüzde, aslında ne kadar az birleştirme işlemine ihtiyaç duyduğunuza şaşıracaksınız.

MongoDB’ye yeniyseniz, Python ile MongoDB’ye Giriş kursuna göz atmanızı öneririm.

SSS

Blog uygulamamın veri modelini ilişkisel bir veritabanından MongoDB’ye aktarabilir miyim?

Id referanslarıyla düz belgeler oluşturabilirsiniz ve çalışır; ancak MongoDB ile elde edebileceğiniz en yüksek performanstan yararlanmış olmazsınız.

Neden her şeyi tek bir belgede saklamıyoruz?

MongoDB’de boyut sınırları vardır ve sınırsız dizileriniz olduğunda bu sınırlara kolayca ulaşabilirsiniz.

Kova deseninden bahsedildi; peki başkaları da var mı?

Başka desenler de olabilir, ancak büyük diziler söz konusu olduğunda kova deseni iyi bir seçenektir.

MongoDB’nin belge boyutu sınırları nelerdir?

MongoDB belgelerinin maksimum boyutu 16 MB’tır.

İç içe geçmiş verilerde (ör. bir yorumu düzenleme) güncellemeleri nasıl ele alırım?

Gömülü veriler için $set gibi güncelleme operatörlerini kullanabilirsiniz; kovalara ayrılmış yorumlarda ise kovayı bulup içindeki belirli yorumu güncelleyebilirsiniz.

Nic Raboy

Yazar

Nic Raboy

Nic Raboy , MongoDB'de Geliştirici İlişkileri Lideridir ve MongoDB'yi projelerine dahil etmelerinde geliştiricilerin başarılı olmasına yardımcı olacak harika içerikler üreten Python, Java, C# ve PHP geliştiricilerinden oluşan bir ekibi yönetir. Golang ve JavaScript konusunda deneyime sahiptir ve sık sık geliştirme maceraları hakkında yazılar yazar.

Konular

İlgili