MongoDB (Mongoose) Schema Mantığı - Gerçek Bir İstatistik Sistemi Üzerinden
Discord botlarında gelişmiş istatistik sistemleri için Schema tasarımı
Discord botlarında gelişmiş istatistik sistemleri için Schema tasarımı
Merhaba arkadaşlar,
Bu konuda MongoDB kullanırken bir Schema'nın nasıl tasarlandığını, neden bu şekilde oluşturulduğunu ve her alanın ne amaçla kullanıldığını gerçek bir örnek üzerinden anlatacağım.
İnceleyeceğimiz örnek, kullanıcıların günlük istatistiklerini tutan bir yapıdır.
Kod paylaşmaktan ziyade, arkasındaki mantığı anlatmaya çalışacağım.
📖 Schema'nın Genel Amacı
Bu Schema'nın amacı, her kullanıcı için günlük istatistikleri tek bir belge (Document) içerisinde saklamaktır.
Örneğin;
- Bugün kaç mesaj attı?
- Kaç dakika ses odasında kaldı?
- Kaç davet yaptı?
- Kaç ticket açtı?
- Kaç kayıt gerçekleştirdi?
- Kaç etkinliğe katıldı?
gibi birçok bilgi tek doküman içerisinde tutulmaktadır.
Böylece geçmiş günlerin istatistiklerine de kolayca ulaşılabilir.
Kod:
const { Schema, model } = require("mongoose");
const statDetailSchema = new Schema({
total: { type: Number, default: 0 },
channels: { type: Map, of: Number, default: {} }
}, { _id: false });
const schema = new Schema({
guildID: { type: String, required: true },
userID: { type: String, required: true },
date: { type: String, required: true },
message: { type: statDetailSchema, default: () => ({}) },
voice: { type: statDetailSchema, default: () => ({}) },
streamer: { type: statDetailSchema, default: () => ({}) },
ticket: { type: Number, default: 0 },
invite: { type: Number, default: 0 },
inviteBonus: { type: Number, default: 0 },
inviteFake: { type: Number, default: 0 },
inviteLeave: { type: Number, default: 0 },
register: { type: Number, default: 0 },
invites: { type: Array, default: [] },
partner: { type: Number, default: 0 },
event: { type: Number, default: 0 },
punishment: { type: Number, default: 0 },
bump: { type: Number, default: 0 },
respect: { type: Number, default: 0 },
task: { type: Number, default: 0 },
partnerHistory: { type: Array, default: [] },
cooldowns: {
respect: { type: Date, default: null },
ticket: { type: Date, default: null }
}
});
schema.index({ guildID: 1, userID: 1, date: 1 }, { unique: true });
schema.index({ guildID: 1, date: 1 });
schema.index({ guildID: 1 });
module.exports = model("StatHistory", schema);🆔 guildID, userID ve date Neden Birlikte Kullanılıyor?
Schema'daki ilk üç alan şunlardır.
Kod:
guildID
userID
dateÖrneğin;
Kod:
Guild : 123456789
User : 987654321
Date : 2026-07-08Ertesi gün geldiğinde aynı kullanıcı için yeni bir kayıt oluşturulur.
Böylece geçmiş istatistikler silinmeden saklanabilir.
📊 message ve voice Neden Object Değil de Ayrı Schema?
Dikkat edilirse;
Kod:
message
voice
streamerBunun yerine ortak bir Schema kullanmaktadır.
Bu Schema iki bilgi tutmaktadır.
- Toplam değer
- Kanal bazlı değerler
Yani sadece;
"Bugün 450 mesaj attı."
bilgisi tutulmaz.
Aynı zamanda;
Kod:
#genel → 120
#sohbet → 280
#müzik → 50Bu nedenle ortak bir yapı oluşturularak aynı Schema üç farklı alanda tekrar kullanılmıştır.
Bu yöntem hem kod tekrarını önler hem de bakımını kolaylaştırır.
🗂️ Map Kullanımı Neden Tercih Edilmiş?
Schema içerisinde dikkat çeken yapılardan biri de şudur.
Kod:
channels: {
type: Map,
of: Number
}Örneğin veritabanında şu şekilde saklanabilir.
Kod:
{
"123456789": 120,
"987654321": 45,
"741852963": 18
}Bu yapı sayesinde istediğiniz kadar kanal eklenebilir.
Yeni kanal açıldığında Schema'yı güncellemeniz gerekmez.
🔢 Number Alanları Ne İçin Kullanılıyor?
Schema içerisinde birçok Number alanı bulunmaktadır.
Örneğin;
- ticket
- invite
- partner
- register
- event
- task
- respect
Bunların tamamı sayaç mantığıyla çalışmaktadır.
Kullanıcı her işlem yaptığında ilgili sayı artırılır.
Örneğin;
- Yeni ticket açtı → ticket +1
- Birini davet etti → invite +1
- Bir kayıt yaptı → register +1
- Etkinliğe katıldı → event +1
Bu yöntem veritabanında oldukça düşük maliyetlidir.
📚 Array Kullanımı
Schema'da iki adet Array alanı bulunmaktadır.
Kod:
invites
partnerHistoryArray kullanılmasının nedeni, tek bir sayı yerine birçok veriyi saklayabilmektir.
Örneğin;
Kod:
[
"123456789",
"987654321",
"741852963"
]veya
Kod:
[
{
userID: "...",
date: "..."
}
]gibi geçmiş kayıtlar tutulabilir.
⏳ Cooldown Sistemi
Schema'nın en kullanışlı bölümlerinden biri de cooldown alanıdır.
Örneğin;
Kod:
cooldowns: {
respect,
ticket
}Burada her özellik için son kullanım zamanı tutulmaktadır.
Örneğin kullanıcı "respect" komutunu kullandığında mevcut tarih kaydedilir.
Bir sonraki kullanımda bu tarih kontrol edilerek bekleme süresi hesaplanabilir.
Böylece ayrı bir veritabanı oluşturmadan cooldown sistemi kurulmuş olur.
⚡ Index Nedir?
Schema'nın sonunda üç adet Index tanımlanmıştır.
Index'i veritabanındaki bir kitabın içindekiler sayfası gibi düşünebilirsiniz.
Eğer Index kullanılmazsa MongoDB aradığı veriyi bulmak için tüm kayıtları tek tek dolaşır.
Ancak Index oluşturulduğunda arama işlemleri çok daha hızlı gerçekleşir.
Bu Schema'da en önemli Index şudur.
Kod:
guildID + userID + dateBu Index aynı kullanıcı için aynı güne ait ikinci bir kayıt oluşturulmasını engeller.
Ayrıca kullanıcı istatistikleri sorgulanırken performansı ciddi ölçüde artırır.
✔ Sonuç
Bu Schema aslında tek bir istatistik sistemi değil, birçok sistemi aynı doküman içerisinde birleştirmektedir.
- Mesaj istatistikleri
- Ses istatistikleri
- Streamer istatistikleri
- Davet sistemi
- Ticket sistemi
- Partner sistemi
- Görev sistemi
- Cooldown sistemi
- Geçmiş kayıtlar
Bütün bu bilgiler tek bir belge içerisinde düzenli şekilde saklanmaktadır.
Bu yaklaşım sayesinde hem veritabanı daha düzenli olur hem de sorgular daha hızlı çalışır. Özellikle büyük Discord sunucularında performans ve bakım açısından önemli avantajlar sağlar.
Ücretli / Ücretsiz Eklenti İşleri İçin:
Discord: never.meant.to.belong
WhatsApp: Mesaj Gönder
Discord: never.meant.to.belong
WhatsApp: Mesaj Gönder
Son Düzenleme: 08-07-2026, 08:56, Düzenleyen: Maravilha
)

