MongoDB'de TTL (time to live) index, belirli bir süre geçtikten sonra belgeleri koleksiyondan otomatik olarak siler. Tarih tipinde bir alana expireAfterSeconds seçeneğiyle index eklemeniz yeterlidir: db.oturumlar.createIndex({ olusturma: 1 }, { expireAfterSeconds: 3600 }) komutu, olusturma değerinin üzerinden bir saat geçen belgeleri sildirir. Silme işini mongod içindeki bir arka plan iş parçacığı yapar ve belgeler süre dolduğu saniyede değil, kısa bir gecikmeyle kaldırılır.
Belgeler TTL özelliğini özellikle makine tarafından üretilen olay verisi, loglar ve oturum bilgileri gibi yalnızca sınırlı bir süre saklanması gereken veriler için önerir. Bu yazıda TTL index oluşturmayı, belirli bir saatte silmeyi, arka plandaki silme sürecinin nasıl işlediğini, süreyi sonradan değiştirmeyi ve sık yapılan hataları anlatıyoruz. Elle belge silme için deleteOne ve deleteMany yazısına bakabilirsiniz.
TTL index oluşturma
TTL index tek alanlı özel bir indextir. Indexlenen alan BSON tarih (Date) tipinde olmalı ya da tarih değerleri içeren bir dizi olmalıdır. Süre expireAfterSeconds seçeneğiyle saniye cinsinden verilir ve belgelere göre 0 ile 2147483647 arasında (iki uç dahil) bir tam sayı olmalıdır.
use uygulama
// Oturumlar oluşturulduktan 30 dakika sonra silinsin
db.oturumlar.createIndex(
{ olusturma: 1 },
{ expireAfterSeconds: 1800 }
)
// Belgeyi eklerken alanı o anki zamanla doldurun
db.oturumlar.insertOne( {
kullanici: "elif",
token: "a1b2c3",
olusturma: new Date()
} )Bir belge, indexlenen alandaki tarihten expireAfterSeconds kadar saniye geçtiğinde süresi dolmuş sayılır. Yukarıdaki örnekte her oturum belgesi, eklendiği andan yaklaşık 30 dakika sonra arka plan görevi tarafından silinir. Alanı her istekte güncellerseniz (örneğin kullanıcı her işlem yaptığında olusturma yerine bir sonErisim alanını new Date() ile yenilerseniz) süre o andan itibaren yeniden başlar; böylece "30 dakika hareketsiz kalan oturumu sil" davranışı elde edersiniz.
Belirli bir saatte silme
Bazen her belgenin kendi bitiş zamanı vardır: bir kampanya kodu ayın sonunda, bir doğrulama bağlantısı belirli bir saatte geçersiz olur. Bunun için expireAfterSeconds değerini 0 yaparsınız ve her belgenin indexli alanına doğrudan silinmesi gereken zamanı yazarsınız. Alan geçmiş bir tarih içeriyorsa MongoDB belgeyi zaten süresi dolmuş kabul eder.
db.kuponlar.createIndex( { sonKullanma: 1 }, { expireAfterSeconds: 0 } )
db.kuponlar.insertOne( {
kod: "KASIM20",
indirim: 20,
sonKullanma: new Date("2026-11-30T21:00:00Z")
} )Bu yaklaşımın avantajı, süreyi belge düzeyinde belirleyebilmenizdir: aynı koleksiyonda bir kupon bir hafta, diğeri bir ay yaşayabilir. Tarihi yazarken saat dilimini açıkça belirtmek (örnekteki Z son eki UTC anlamına gelir) karışıklığı önler; BSON tarih tipinin davranışını BSON veri tipleri yazısında anlattık.
Hangi belgeler silinir, hangileri silinmez?

- Indexli alan bir tarih dizisiyse MongoDB dizideki en erken tarihi esas alır; belgeler bunu, dizideki tarihlerden en az biri süreyi aşınca belgenin silineceği biçiminde de ifade eder.
- Indexli alan bir veya daha fazla tarih değeri içermiyorsa, örneğin metin olarak saklanmış bir tarihse, belge hiçbir zaman silinmez.
- Belgede indexli alan hiç yoksa belge silinmez.
- Time series koleksiyonlarında TTL index, bir veri kovasının (bucket) içindeki bütün belgelerin süresi dolunca kovanın tamamını kaldırır; kovanın üst zaman sınırına
expireAfterSecondseklenerek hesaplanır.
İkinci madde pratikte en çok sorun çıkaran durumdur. Uygulamanız tarihi "2026-11-07" gibi bir metin olarak yazıyorsa TTL index hata vermez ama hiçbir şeyi silmez. Belgeler bunu önlemek için şema doğrulaması kullanmayı önerir: aşağıdaki doğrulayıcı, alanın her belgede bulunmasını ve tarih tipinde olmasını zorunlu kılar.
db.createCollection( "olaylar", {
validator: {
$jsonSchema: {
bsonType: "object",
required: [ "zaman" ],
properties: {
zaman: {
bsonType: "date",
description: "Geçerli bir tarih olmalı."
}
}
}
}
} )
db.olaylar.createIndex( { zaman: 1 }, { expireAfterSeconds: 604800 } )Bu örnekte olaylar bir hafta (604800 saniye) saklanır ve doğrulayıcı sayesinde tarihi metin olarak yazan hatalı bir ekleme reddedilir. Doğrulama kurallarının ayrıntısı schema validation yazısında.
Silme süreci nasıl işler?

mongod içindeki bir arka plan iş parçacığı TTL indexlerdeki değerleri okur ve süresi dolan belgeleri koleksiyondan siler. Belgeler bu görevin her 60 saniyede bir çalıştığını belirtir. Bu yüzden TTL, süresi dolan bir belgenin hemen silineceğini garanti etmez: süre dolması ile silinme arasında gecikme olabilir ve sunucunun iş yüküne bağlı olarak belge 60 saniyelik aralığın da ötesinde bir süre koleksiyonda kalabilir. TTL görevinin başlattığı silmeler, diğer silme işlemleri gibi ön planda çalışır.
Her çalışmada süreç TTL indexleri tek tek kontrol eder ve her index için şu koşullardan biri gerçekleşene kadar silmeye devam eder: o indexten 50000 belge silinmesi, o index için bir saniye harcanması ya da süresi dolan bütün belgelerin silinmesi. Ardından bir sonraki indexe geçer. Bütün TTL indexlerin bir kez dolaşılması bir alt geçiş (sub-pass) sayılır ve kalan belgeler için yeni bir alt geçiş başlar; bütün aday belgeler silindiğinde geçiş (pass) tamamlanır. Süreç ayrıca tek bir büyük silmede fazla zaman harcamamak için silme döngüsünü her 60 saniyede bir keser.
MongoDB 6.1 ve sonrasında verimlilik için birden çok belge silmesi gruplanabilir ve explain çıktısında bunun için BATCHED_DELETE aşaması görünür. Süren TTL silmeleri db.currentOp() çıktısında yer alır.
TTL sürecini izlemek
TTL görevinin ne yaptığını serverStatus çıktısındaki metriklerden takip edebilirsiniz: metrics.ttl.deletedDocuments silinen belge sayısını, metrics.ttl.passes ve metrics.ttl.subPasses ise geçiş ve alt geçiş sayılarını tutar.
const m = db.serverStatus().metrics.ttl
printjson( {
silinen: m.deletedDocuments,
gecis: m.passes,
altGecis: m.subPasses
} )Silinen belge sayısı uzun süre artmıyorsa indexli alanın tipini, indexin gerçekten TTL olup olmadığını (getIndexes() çıktısında expireAfterSeconds görünmeli) ve aşağıda anlatılan replica set ve standalone koşullarını kontrol edin.
Replica set ve standalone davranışı
Replica set üyelerinde TTL arka plan iş parçacığı yalnızca üye primary durumundayken belge siler; secondary durumundaki üyelerde boşta bekler ve secondary üyeler silme işlemlerini primary'den çoğaltma yoluyla alır. Belgelerin bir başka notuna göre, mongod standalone modda çalışıyorsa ve system.local.replset koleksiyonunda veri varsa TTL izleyicisi durur. Bu durum, örneğin bakım için bir replica set üyesini geçici olarak tek başına başlattığınızda ortaya çıkabilir. Belgelere göre MongoDB, index primary üzerinde oluşturulmayı bitirdiği anda süresi dolan belgeleri silmeye başlar; ilk silmeler index tamamlandıktan sonraki 0 ile 60 saniye içinde gerçekleşir. Replica set yapısı için replica set kurulumu yazısına bakın.
TTL index, normal bir index gibi sorguları da destekler. Yani olusturma alanına göre filtreleyen veya sıralayan sorgularınız aynı indexten yararlanabilir. Index gizlenirse (hidden) planlayıcı onu sorgular için kullanmaz ama belgeler gizli bir TTL indexin belgeleri silmeye devam ettiğini belirtir.
Süreyi sonradan değiştirmek
Var olan bir TTL indexin süresini createIndex() ile değiştiremezsiniz; aynı komutu farklı bir değerle çalıştırmak indexi güncellemez. Bunun için collMod komutu kullanılır:
db.runCommand( {
collMod: "oturumlar",
index: {
keyPattern: { olusturma: 1 },
expireAfterSeconds: 3600
}
} )Belgeler bu işlemle ilgili üç noktayı vurgular. Süreyi değiştirmek indexin tamamen yeniden kurulmasını tetiklemez. Ancak süreyi kısaltmak çok sayıda belgeyi anında silinmeye uygun hale getirebilir ve artan silme işlemleri performans sorununa yol açabilir; önerilen yol, değişiklikten önce belgeleri küçük partiler halinde elle silmektir. Çok sayıda belge silmek depolama dosyalarını parçalayabilir; alanı geri kazanmak için koleksiyonda compact çalıştırmanız veya bir initial sync yapmanız gerekebilir. Bu tür toplu değişikliklerden önce yedek almanızı öneririz.
Normal indexi TTL indexe çevirmek
MongoDB 5.1 ve sonrasında, var olan tek alanlı normal bir indexe expireAfterSeconds ekleyerek onu TTL indexe dönüştürebilirsiniz; komut yukarıdakiyle aynıdır. Bu yol gereklidir, çünkü bir alanda zaten normal bir index varsa aynı alana ayrı bir TTL index oluşturamazsınız: belgelere göre aynı anahtar tanımına sahip, yalnızca seçenekleriyle ayrışan iki index kurulamaz.
Kısıtlar

- TTL indexler tek alanlıdır. Compound indexler TTL özelliğini desteklemez ve
expireAfterSecondsseçeneğini yok sayar. _idalanı TTL index için kullanılamaz.- Süre
createIndex()ile değiştirilemez;collModgerekir. - Aynı alanda normal bir index varsa ayrı bir TTL index açılamaz; normal index
collModile dönüştürülür. - MongoDB 7.0 ve sonrasında time series koleksiyonlarında
metaFieldüzerinde filtreli partial TTL index oluşturulabilir; daha önceki sürümlerde time series için TTL yalnızcatimeFieldüzerinde mümkündü.
Partial TTL: yalnızca bazı belgeleri sildirmek
Bir index hem partial hem TTL olabilir. Bu durumda yalnızca filtreye uyan belgelerin süresi dolar, diğerleri koleksiyonda kalır. Örneğin bir olay koleksiyonunda tıklama kayıtlarını kısa süre, diğer olayları kalıcı saklamak isteyebilirsiniz:
db.olaylar2.createIndex(
{ zaman: 1 },
{
expireAfterSeconds: 86400,
partialFilterExpression: { tur: "tiklama" }
}
)Bu indexle tur değeri "tiklama" olan belgeler bir gün sonra silinir; "goruntuleme" gibi diğer türler etkilenmez. Partial indexin genel kuralları unique, partial ve sparse index yazısında anlatılıyor.
Time series ve clustered koleksiyonlar
Time series ve clustered koleksiyonlarda süre, koleksiyon oluşturulurken expireAfterSeconds seçeneğiyle de verilebilir; belgelere göre bu koleksiyon seçeneği yalnızca bu iki koleksiyon türünde vardır. Time series koleksiyonunda koleksiyon süresinin yanında metaField filtreli bir partial TTL index tanımlarak belirli bir sensörün verisini daha kısa sürede sildirebilirsiniz. Dikkat: koleksiyonun süresi partial TTL indexin süresinden kısaysa, kısa olan süre geçerli olur ve TTL indexin bir etkisi kalmaz.
db.createCollection( "sicaklik24s", {
timeseries: {
timeField: "zaman",
metaField: "sensor",
granularity: "hours"
},
expireAfterSeconds: 86400
} )
// Test sensörünün verisi 1 saat sonra silinsin
db.sicaklik24s.createIndex(
{ zaman: 1 },
{
partialFilterExpression: { sensor: { $eq: "test-01" } },
expireAfterSeconds: 3600
}
)Time series koleksiyonlarının kendisini time series koleksiyonları yazısında ayrıntılı ele alıyoruz.
NaN uyarısı
Belgeler expireAfterSeconds değerinin asla NaN yapılmaması konusunda açık bir veri kaybı uyarısı içerir. Eski sürümlerde bu değer farklı yorumlandığı için, örneğin MongoDB 5.0.0 ile 5.0.13 arası (ve 6.0.0 ile 6.0.1) sürümlerde NaN sıfır gibi ele alındı ve indexteki bütün belgeler anında süresi dolmuş sayıldı. MongoDB 5.0.14 ve 6.0.2 ile sunucu bu değere sahip TTL indexleri kullanmaz; ancak bazı initial sync, yükseltme ve eski bir dump'tan geri yükleme senaryolarında beklenmedik silmeler hâlâ mümkündür. Belgeler, mongosh'ta bütün veritabanlarını dolaşıp Object.is(entry.expireAfterSeconds, NaN) kontrolüyle hatalı indexleri bulan bir betik verir; bulunan indexler collMod ile düzeltilmeli veya silinip yeniden oluşturulmalıdır.
Sık yapılan hatalar
- Tarihi metin olarak saklamak: TTL yalnızca BSON Date değerleriyle çalışır; metin tarihli belgeler hiç silinmez.
- Anında silinme beklemek: Görev 60 saniyede bir çalışır ve yük altında daha da gecikebilir.
- Compound indexe expireAfterSeconds eklemek: Seçenek yok sayılır, hiçbir belge silinmez.
- Süreyi createIndex ile değiştirmeye çalışmak:
collModkullanın. - Büyük koleksiyonda süreyi aniden kısaltmak: Önce partiler halinde silin.
- Secondary üyede silme beklemek: Silmeyi primary yapar, secondary çoğaltma yoluyla alır.
Sık Sorulan Sorular
TTL index belgeyi tam süresinde siler mi?
Hayır. Arka plan görevi her 60 saniyede bir çalışır ve iş yüküne göre silme daha da gecikebilir. TTL, kesin zamanlı silme değil, otomatik temizlik aracıdır.
Belgenin silinmesini nasıl ertelerim?
Indexli tarih alanını daha yeni bir zamanla güncelleyin. Süre, alandaki tarihten itibaren hesaplandığı için güncelleme silinmeyi ileri atar.
TTL index sorgularda da kullanılır mı?
Evet. Belgelere göre TTL index sorguları normal bir index gibi destekler. Tarih alanına göre filtreleyen veya sıralayan sorgularınız için ayrı bir index açmanıza gerek kalmayabilir.
Silinen belgelerin disk alanı geri gelir mi?
Belgeler, çok sayıda silmenin depolama dosyalarını parçalayabileceğini ve alanı geri kazanmak için compact komutu ya da initial sync gerekebileceğini belirtir.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: MongoDB öğrenme rehberi · MongoDB index oluşturma · Unique, partial ve sparse index · Time series koleksiyonları · deleteOne ve deleteMany · Schema validation