Bir Discord bot MongoDB kurulumu, botunuz yeniden başladığında verilerin kaybolmadığı kalıcı bir hafıza kazandırmanın en pratik yollarından biridir. Seviye sistemleri, ekonomi botları, uyarı kayıtları veya kullanıcı ayarları gibi her şeyin bir yere yazılması gerekir; basit bir JSON dosyası küçük botlarda iş görse de eşzamanlı yazma, ölçeklenme ve sorgulama gerektiğinde yetersiz kalır. Bu yazıda discord.js ile çalışan bir bota Mongoose üzerinden MongoDB bağlayıp kullanıcı verisini doğru biçimde saklamayı adım adım kuruyoruz.
Neden MongoDB ve Mongoose?
MongoDB, verileri belge (document) olarak JSON benzeri yapıda saklayan bir NoSQL veritabanıdır. Discord botları için bu doğal bir eşleşmedir: bir kullanıcının verisi zaten iç içe geçmiş alanlardan oluşur (bakiye, envanter, ayarlar) ve sabit bir tablo şemasına zorlamak yerine esnek belgeler kullanmak işi kolaylaştırır. Mongoose ise MongoDB için bir ODM (Object Data Modeling) kütüphanesidir; ham sürücünün üzerine şema doğrulaması, tip kontrolü ve okunabilir bir API ekler.
- SQLite tek sunuculu, dosya tabanlı küçük botlar için idealdir.
- MongoDB ise birden çok sunucuda çalışan, sharding gerektiren ya da bulutta (MongoDB Atlas) barındırılan botlarda daha rahat ölçeklenir.
- Mongoose, şema sayesinde "bir alan yanlış tipte yazıldı" gibi hataları üretime gitmeden yakalar.
Kurulum ve bağlantı dizesi
Önce Mongoose'u projeye ekleyin:
npm install mongoose
Ardından bir veritabanına ihtiyacınız var. En hızlı yol, ücretsiz katmanı olan MongoDB Atlas'tır: bir cluster oluşturun, bir veritabanı kullanıcısı tanımlayın ve "Connect" ekranından bağlantı dizesini (connection string) kopyalayın. Dize şu biçimdedir:
mongodb+srv://kullanici:sifre@cluster0.xxxxx.mongodb.net/botdb
Bu dizeyi asla kodun içine yazmayın; token gibi gizli bilgileri her zaman bir .env dosyasında tutun ve .gitignore'a ekleyin:
# .env
DISCORD_TOKEN=...
MONGO_URI=mongodb+srv://kullanici:sifre@cluster0.xxxxx.mongodb.net/botdb
Bota MongoDB bağlamak
Bağlantıyı bot hazır olmadan önce, açılışta bir kez kurun. Bağlantı asenkron olduğu için await ile bekleyip hatayı yakalamak önemlidir; aksi halde veritabanı erişilemezse bot sessizce çöker:
require('dotenv').config();
const mongoose = require('mongoose');
const { Client, GatewayIntentBits } = require('discord.js');
const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers],
});
async function start() {
try {
await mongoose.connect(process.env.MONGO_URI);
console.log('MongoDB bağlantısı kuruldu');
} catch (err) {
console.error('MongoDB bağlantı hatası:', err);
process.exit(1);
}
await client.login(process.env.DISCORD_TOKEN);
}
start();
Mongoose 6 ve sonrasında useNewUrlParser gibi eski seçenekler artık varsayılan olduğu için ek ayar gerekmez. Bağlantı havuzunu (connection pool) Mongoose kendisi yönetir; her komutta yeniden bağlanmaya çalışmayın.
Şema ve model tanımlamak
Mongoose'da veriler bir şema ile tanımlanır ve bu şemadan bir model üretilir. Tipik bir kullanıcı modelini ayrı bir dosyada tutmak en temiz yaklaşımdır:
// models/User.js
const { Schema, model } = require('mongoose');
const userSchema = new Schema({
userId: { type: String, required: true, unique: true },
guildId: { type: String, required: true },
balance: { type: Number, default: 0 },
xp: { type: Number, default: 0 },
level: { type: Number, default: 1 },
}, { timestamps: true });
module.exports = model('User', userSchema);
unique: true her kullanıcı için yalnızca bir belge olmasını sağlar ve aynı zamanda bir index oluşturur, böylece sorgular hızlanır. timestamps: true ise createdAt ve updatedAt alanlarını otomatik ekler.
Veri okuma ve yazma: upsert kalıbı
En sık yaptığınız işlem, "bu kullanıcının belgesi varsa getir, yoksa oluştur" mantığıdır. Bunu iki ayrı sorgu yapmak yerine tek bir upsert ile çözmek hem daha hızlı hem de eşzamanlı çağrılara karşı daha güvenlidir. findOneAndUpdate ile upsert: true seçeneği tam olarak bunu yapar:
const User = require('./models/User');
async function getUser(userId, guildId) {
return User.findOneAndUpdate(
{ userId, guildId },
{ $setOnInsert: { userId, guildId } },
{ upsert: true, new: true }
);
}
$setOnInsert yalnızca belge ilk kez oluşturulurken çalışır; var olan belgeyi ezmez. new: true ise güncellenmiş (ya da yeni oluşturulan) belgeyi döndürür. Bir değeri artırmak istediğinizde, belgeyi çekip elle değiştirmek yerine $inc operatörünü kullanın; bu atomiktir ve yarış koşullarını (race condition) önler:
// Bir slash komutu içinde: kullanıcıya bakiye ekle
await User.updateOne(
{ userId: interaction.user.id, guildId: interaction.guildId },
{ $inc: { balance: 100 } },
{ upsert: true }
);
Tam bir bakiye komutu şöyle görünür:
if (interaction.commandName === 'balance') {
const doc = await getUser(interaction.user.id, interaction.guildId);
await interaction.reply(`Bakiyen: ${doc.balance} 💰`);
}
Performans ve üretim ipuçları
Botunuz büyüdükçe birkaç alışkanlık fark yaratır:
- Index ekleyin: Sık sorguladığınız alanlara (örneğin liderlik tablosu için
xp) şemadaindex: trueverin. Index'siz sorgular tüm koleksiyonu tarar. - Sadece okuyacaksanız
.lean()kullanın:User.find().sort({ xp: -1 }).limit(10).lean()tam Mongoose belgeleri yerine düz JavaScript nesneleri döndürür ve belirgin biçimde daha hızlıdır. - Bağlantı olaylarını dinleyin:
mongoose.connection.on('error', ...)ile kopuşları loglayın; sessiz hatalar en zor bulunan hatalardır. - IP erişimini kısıtlayın: Atlas'ta Network Access bölümünden yalnızca botunuzun sunucu IP'sine izin verin,
0.0.0.0/0kullanmayın.
Sık Sorulan Sorular
MongoDB mi SQLite mı seçmeliyim?
Tek bir VPS'te çalışan küçük/orta bir bot için SQLite genelde yeterli ve kurulumu daha basittir. Verileriniz büyüdükçe, sharding düşünüyorsanız ya da yönetilen bir bulut veritabanı istiyorsanız MongoDB daha rahat ölçeklenir. İhtiyaca göre seçin; ikisi de kalıcı saklama için doğru araçlardır.
Her komutta yeniden bağlanmam gerekir mi?
Hayır. mongoose.connect bir kez, bot açılırken çağrılır. Mongoose bağlantı havuzunu yönetir ve modelleriniz bu tek bağlantıyı paylaşır. Her komutta yeniden bağlanmak ciddi performans sorunlarına yol açar.
Şemayı sonradan değiştirebilir miyim?
Evet. MongoDB esnek olduğu için yeni bir alan eklemek var olan belgeleri bozmaz; o alan eksik belgeler için şemadaki default değeri devreye girer. Yine de tip değişiklikleri gibi büyük dönüşümlerde bir migration scripti yazmanız önerilir.
Verisini güvenle saklayan bir Discord botu mu istiyorsunuz? Ekonomi, seviye veya moderasyon sistemleri için MongoDB altyapısı kuruyorum. Projenizi birlikte hayata geçirelim — benimle iletişime geçin.