MongoDB time series koleksiyonu, zamana göre sıralı ölçümleri (sensör değerleri, sunucu metrikleri, fiyatlar, ziyaret sayıları) normal koleksiyona göre daha az disk ve daha verimli sorguyla saklamak için tasarlanmış özel bir koleksiyon türüdür. Oluşturmak için db.createCollection() çağrısına timeseries seçeneği verilir: zamanın tutulduğu alanı timeField, veri kaynağını tanımlayan alanı metaField ile belirtirsiniz, isterseniz granularity ve otomatik silme için expireAfterSeconds eklersiniz. Özellik MongoDB 5.0 ile gelmiştir.

Bu yazıda koleksiyonu oluşturmayı, verinin arka planda "bucket" denen gruplar halinde nasıl saklandığını, metaField ve granularity seçiminin performansa etkisini, sorgulama ve index kurallarını, eski verinin otomatik silinmesini ve time series koleksiyonlarının normal koleksiyonlardan ayrıldığı kısıtları anlatıyoruz. Örnek senaryomuz, birkaç VPS'ten dakikada bir CPU ve bellek kullanımı toplayan bir izleme sistemi.

Temel kavramlar

Temel kavramlar: Sunucu izleme, Hava istasyonu, Web analitiği

Time series verisi üç parçadan oluşur. Zaman, ölçümün alındığı andır. Metadata, bir veri serisini tanımlayan ve nadiren değişen etikettir; sensör kimliği, hisse kodu ya da sunucu adı gibi. MongoDB'de bu bilgi metaField içinde tutulur. Metrikler ise zamanla değişen değerlerdir: sıcaklık, fiyat, CPU yüzdesi. Belirli bir andaki zaman, metadata ve tüm metrikleri içeren belgeye ölçüm (measurement) denir.

SenaryoMetrikMetadata
Sunucu izlemeCPU, bellek, disk kullanımıSunucu adı, veri merkezi
Hava istasyonuSıcaklık, nemSensör kimliği, konum
Web analitiğiGörüntülenme sayısıSayfa adresi

Belgeler time series koleksiyonlarının sırasız veriler ve zamana bağlı olmayan veriler için tasarlanmadığını belirtir. Kullanıcı profilleri, sipariş kayıtları ya da ürün kataloğu gibi verileri normal koleksiyonda tutun.

Time series koleksiyonu oluşturmak

Time series koleksiyonu yalnızca featureCompatibilityVersion değeri 5.0 veya üzeri olan sistemlerde oluşturulabilir. Koleksiyon türü oluşturma anında belirlenir; var olan bir koleksiyonu sonradan time series'e çeviremezsiniz.

javascript
use izleme
db.createCollection(
   "metrikler",
   {
      timeseries: {
         timeField: "zaman",
         metaField: "kaynak",
         granularity: "minutes"
      },
      expireAfterSeconds: 2592000
   }
)
SeçenekZorunlu muAçıklama
timeseries.timeFieldEvetHer belgede geçerli bir BSON tarih tutan alanın adı
timeseries.metaFieldHayırSeriyi tanımlayan metadata alanı; _id olamaz, timeField ile aynı olamaz, her veri tipinde olabilir
timeseries.granularityHayırseconds (varsayılan), minutes veya hours; özel bucket parametreleriyle birlikte kullanılmaz
timeseries.bucketMaxSpanSecondsHayırAynı bucket içindeki zaman damgaları arasındaki en büyük süre; 1 ile 31536000 arası; 6.3 ve sonrası
timeseries.bucketRoundingSecondsHayırYeni bucket'ın başlangıç zamanını belirleyen yuvarlama aralığı; bucketMaxSpanSeconds ile aynı değer olmalı
expireAfterSecondsHayırBelgelerin kaç saniye sonra otomatik silineceği

Belgeler, time series koleksiyonundaki her belgenin timeField alanında geçerli bir BSON Date taşımasını şart koşar; tarihi dize olarak yazmayın. mongosh'ta new Date() ya da ISODate() kullanın; tarih tipinin ayrıntıları MongoDB BSON veri tipleri yazısında. MongoDB 8.3'ten beri $ ile başlayan bir timeField adı kullanılamaz. timeField ve metaField yalnızca oluşturma anında belirlenir, sonra değiştirilemez.

Ölçüm eklemek

Her belge tek bir ölçümü temsil etmelidir. Birden çok ölçümü aynı anda eklemek için insertMany() kullanılır:

javascript
db.metrikler.insertMany( [
   { zaman: ISODate("2026-11-07T09:00:00Z"), kaynak: { sunucu: "vps-ist-1", bolge: "ist" }, cpu: 23.5, bellek: 61.2 },
   { zaman: ISODate("2026-11-07T09:01:00Z"), kaynak: { sunucu: "vps-ist-1", bolge: "ist" }, cpu: 27.1, bellek: 61.8 },
   { zaman: ISODate("2026-11-07T09:00:00Z"), kaynak: { sunucu: "vps-ank-2", bolge: "ank" }, cpu: 8.4, bellek: 40.3 }
] )

Burada kaynak bir alt belgedir. metaField nesne olabilir ve alt alanlar içerebilir. Ekleme sözdizimi normal koleksiyonla aynıdır; temel bilgiler için MongoDB insertOne ve insertMany yazısına bakın.

Arka planda: bucket'lar

Time series koleksiyonu, gelen ölçümleri otomatik olarak bucket denen gruplara toplar. Bir bucket'taki belgeler aynı metaField değerini paylaşır ve zaman değerleri birbirine yakındır. Uygun bir bucket varsa yeni ölçüm ona eklenir, yoksa yeni bucket açılır. Veri sütun odaklı, zaman sıralı ve sıkıştırılmış bir biçimde saklanır; belgeler bunun disk kullanımını ve okuma G/Ç'sini azalttığını, sorgu verimliliğini artırdığını ve WiredTiger önbelleğinin daha iyi kullanılmasını sağladığını belirtir.

MongoDB 9.0 ile time series koleksiyonları, bucket'lara sıkıştırılmış veriyi içeren tek bir namespace olarak saklanır; artık yazılabilir, materyalize edilmemiş view olarak çalışmazlar. Sorgu yaptığınızda MongoDB veriyi ham bucket biçiminden ölçüm başına bir belge olan mantıksal biçime çevirir, yani siz yine tek tek ölçümler görürsünüz. 9.0 ile ayrıca time series koleksiyonlarını renameCollection ile yeniden adlandırabilirsiniz. Sürüm notları, tek bir veritabanında 5.000'den fazla time series koleksiyonu olan kümelerin 9.0'a yükseltmede daha uzun sürebileceği ve ek yazma gecikmesi yaşayabileceği uyarısını da içerir. Bu değişikliklerin tamamı MongoDB 9.0 yenilikleri yazısında.

Bir bucket'ın boyutu, granularity ayarı ne olursa olsun en fazla 1000 ölçüm ya da 125 KB veri ile sınırlıdır (hangisi önce dolarsa). Çok sayıda benzersiz değer içeren yüksek kardinaliteli verilerde MongoDB, çalışan bucket kümesinin WiredTiger önbelleğine sığması için daha düşük bir sınır uygulayabilir.

metaField seçimi en kritik karardır

metaField seçimi en kritik karardır: metaField içine nadiren ya da hiç değişmeyen alanları koyun., Mümkünse filtrelerde sık kullandığınız kimlikleri ve kararlı değerleri seçin...

Belgelere göre metaField seçimi, sorgu performansını en çok etkileyen karardır. Bucket sayısı benzersiz metaField değerlerinin sayısına bağlıdır. Sık değişen ya da çok ayrıntılı metaField değerleri çok sayıda, seyrek dolu ve kısa ömürlü bucket üretir; bu da depolama ve sorgu verimini düşürür. Belgelerdeki öneriler şöyle özetlenebilir:

  • metaField içine nadiren ya da hiç değişmeyen alanları koyun.
  • Mümkünse filtrelerde sık kullandığınız kimlikleri ve kararlı değerleri seçin; yukarıdaki örnekte sunucu adı ve bölge.
  • Filtrelemede kullanılmayan alanları metaField'a koymayın, onları ölçüm alanı olarak bırakın. Örneğin CPU değeri asla metaField'da olmamalıdır.
  • Dizi kullanmaktan kaçının: belgeler, dizi eşitliği sıraya bağlı olduğu için metaField olarak dizi kullanmanın beklenmedik davranışa yol açabileceğini belirtir.

metaField tanımlandıktan sonra başka bir alanı metaField yapamazsınız. Ancak metaField bir nesneyse içine yeni alt alanlar ekleyebilirsiniz. Bu yüzden kaynak gibi bir nesne alanı kullanmak ileride esneklik sağlar.

granularity ve özel bucket aralıkları

granularity, bir bucket'ın en fazla ne kadarlık zamanı kapsayacağını belirler:

granularityBucket'ın kapsadığı en uzun süre
seconds (varsayılan)1 saat
minutes24 saat
hours30 gün

Doğru değer, aynı kaynaktan gelen ardışık ölçümler arasındaki süreye en yakın olanıdır. Belgelerin örneğinde binlerce sensör her biri beş dakikada bir veri gönderiyorsa "minutes" uygundur. Sorgu alışkanlığınızı da düşünün: genelde bir günlük veri çekiyorsanız "minutes" iyi bir eşleşmedir. "seconds" aynı veri için çok daha fazla bucket üretir; "hours" ise 30 günlük bucket'lar oluşturur ve kısa aralık sorgularında çoğu veriyi okuyup atmak zorunda kalır.

MongoDB 6.3 ve sonrasında granularity yerine iki özel parametre kullanabilirsiniz: bucketMaxSpanSeconds ve bucketRoundingSeconds. İkisi birlikte ve aynı değerle verilmelidir, granularity ile birlikte kullanılmaz. Raporlarınızı her gün gece yarısından başlayarak dört saatlik dilimlerle alıyorsanız ikisini de 14400 yapabilirsiniz:

javascript
db.createCollection(
   "metrikler4s",
   {
      timeseries: {
         timeField: "zaman",
         metaField: "kaynak",
         bucketMaxSpanSeconds: 14400,
         bucketRoundingSeconds: 14400
      }
   }
)

Bu ayarla, saat 16:24:35'te gelen ve mevcut bir bucket'a sığmayan bir ölçüm için MongoDB zaman damgasını 14400 saniyelik aralığa göre aşağı yuvarlar; yeni bucket 16:00:00'da başlar ve 19:59:59'da biter. Bucket sınırlarının rapor dilimleriyle çakışması hem sorgu hem ekleme yükünü azaltır.

Ayarları sonradan collMod ile değiştirebilirsiniz, ama yalnızca bucket'ın kapsadığı süreyi artırabilirsiniz; azaltmak mümkün değildir. Özel parametreleri değiştirirken ikisini de aynı değerle göndermelisiniz. Değişiklik öncesi yedek almayı unutmayın.

javascript
db.runCommand( {
   collMod: "metrikler",
   timeseries: { granularity: "hours" }
} )

// Mevcut ayarları görmek için
db.runCommand( { listCollections: 1, filter: { type: "timeseries" } } )

Sorgulama ve aggregation

Time series koleksiyonunu normal bir koleksiyon gibi sorgularsınız. Sorgular genellikle tek bir seriye odaklanır, bu yüzden en verimli filtre metaField üzerinde eşitlik, ardından timeField üzerinde aralık koşuludur. MongoDB aynı metaField değerine ve yakın zamanlara sahip belgeleri birlikte tuttuğu için bu iki koşul taranacak bucket sayısını hızla daraltır.

javascript
// Bir sunucunun son bir saatlik ölçümleri
db.metrikler.find( {
   "kaynak.sunucu": "vps-ist-1",
   zaman: { $gte: ISODate("2026-11-07T08:00:00Z"), $lt: ISODate("2026-11-07T09:00:00Z") }
} )

// Sunucu başına saatlik ortalama CPU
db.metrikler.aggregate( [
   { $match: { "kaynak.bolge": "ist" } },
   { $group: {
      _id: {
         sunucu: "$kaynak.sunucu",
         saat: { $dateTrunc: { date: "$zaman", unit: "hour", timezone: "Europe/Istanbul" } }
      },
      ortCpu: { $avg: "$cpu" },
      enYuksekCpu: { $max: "$cpu" }
   } },
   { $sort: { "_id.saat": 1 } }
] )

Belgeler time series analizinde sık kullanılan araçlar olarak $dateAdd, $dateDiff, $dateTrunc ve $setWindowFields sayar. $match, timeField üzerindeki $sort ve $group ile başlayan uzun aggregation'larda MongoDB uygun sorgularda otomatik olarak block processing kullanır; bunu elle açıp kapatamazsınız, kullanılıp kullanılmadığını explain çıktısında görebilirsiniz. Gruplama için MongoDB $group ve accumulator yazısına bakın.

Index'ler

Index'ler: Normal koleksiyonların aksine _id alanında varsayılan index yoktur. _id..., Text index ve unique index desteklenmez. Bu yüzden time series koleksiyonunda..., Partial...

MongoDB 6.3 ve sonrasında yeni bir time series koleksiyonu oluşturduğunuzda metaField ve timeField üzerinde otomatik bir bileşik index kurulur. MongoDB 6.0'dan beri herhangi bir alana ikincil index ekleyebilirsiniz. Time series index'leri tek tek belgeleri değil bucket'ları indeksler; metaField dışındaki alanlar için bucket'ın en küçük ve en büyük değerleri indekslenir, bu da index boyutunu küçültür.

javascript
db.metrikler.createIndex( { "kaynak.sunucu": 1, cpu: -1 } )
  • Normal koleksiyonların aksine _id alanında varsayılan index yoktur. _id üzerinde hint veren komutlar, siz elle index oluşturmadıkça hata verir; MongoDB 8.3'ten beri "_id_" adında index oluşturmak ya da bu adla hint vermek de hata döndürür.
  • Text index ve unique index desteklenmez. Bu yüzden time series koleksiyonunda tekrar eden belgeleri unique index ile engelleyemezsiniz.
  • Partial index metaField ve timeField üzerinde oluşturulamaz.
  • timeField değerleri 1970-01-01 öncesine ya da 2038-01-19T03:14:07Z sonrasına taşıyorsa belgeler timeField üzerinde index oluşturmanızı önerir.
  • Belgelerin index önerisi: filtreleme ve eşitlik için metaField index'ini, aralık sorguları için timeField ve diğer indeksli alanları kullanın.

Eski veriyi otomatik silmek

Koleksiyon düzeyindeki expireAfterSeconds, bir belgenin timeField değerine bu kadar saniye eklendiğinde süresinin dolduğunu söyler. Örneğin değer 86400 ise 7 Kasım 10:00 zamanlı bir ölçüm 8 Kasım 10:00'da süresi dolmuş sayılır. Ancak silme belge belge değil bucket bucket yapılır: bir bucket'taki tüm belgelerin süresi dolduğunda, süresi dolan bucket'ları silen arka plan görevi bir sonraki çalışmasında o bucket'ı kaldırır. Bu görev 60 saniyede bir çalışır ve süresi mongod'un iş yüküne bağlıdır; bu yüzden süresi dolmuş veri bir süre daha görünebilir.

javascript
// Var olan koleksiyonda otomatik silmeyi açmak veya süreyi değiştirmek
db.runCommand( { collMod: "metrikler", expireAfterSeconds: 604800 } )

// Kapatmak
db.runCommand( { collMod: "metrikler", expireAfterSeconds: "off" } )

"off" değeri yalnızca koleksiyon düzeyindeki ayar için geçerlidir. MongoDB 7.0'dan beri yalnızca metaField'a dayanan bir partialFilterExpression ile TTL index de oluşturabilirsiniz; böylece örneğin test sunucularının verisini daha erken silebilirsiniz. Normal koleksiyonlardaki TTL index mantığı için MongoDB TTL index yazısına bakın.

Kısıtlar

Time series koleksiyonları genelde normal koleksiyon gibi davranır, ama şu farklara dikkat edin:

  • Güncelleme: Yalnızca metaField üzerinde eşleştirme yapabilir ve yalnızca metaField değerini değiştirebilirsiniz. Güncelleme belgesi yalnızca update operatörleri içermeli, belge sayısını sınırlamamalı (updateMany() ya da multi: true) ve upsert: true kullanmamalıdır. Ölçüm değerini düzeltmek için güncelleme yapamazsınız.
  • Desteklenmeyenler: Change streams, şema doğrulama kuralları, reIndex, istemci tarafı alan şifreleme (CSFLE), Atlas Search.
  • Belge boyutu: Time series koleksiyonundaki bir belge en fazla 4 MB olabilir.
  • Tür değişikliği: Normal koleksiyon time series'e, time series de başka türe çevrilemez. Veriyi taşımak gerekir; time series koleksiyonu capped olarak da oluşturulamaz.
  • $merge: Başka bir koleksiyondan time series koleksiyonuna $merge ile veri yazamazsınız; bunun için $out kullanılır. Time series'ten başka bir koleksiyona $merge ile yazmak serbesttir. Bkz. MongoDB $out ve $merge
  • Transaction: Time series koleksiyonuna transaction içinde yazılamaz, okunabilir. Bkz. MongoDB transaction kullanımı
  • Coğrafi sorgu: Yalnızca $geoNear aşaması kullanılabilir; $near ve $nearSphere çalışmaz.

Sık yapılan hatalar

  • Ölçüm değerini metaField'a koymak: Her ölçüm yeni bir seri gibi görünür ve bucket sayısı patlar.
  • Tarihi dize olarak yazmak: timeField geçerli bir BSON Date olmalıdır.
  • Varsayılan seconds ile seyrek veri toplamak: Dakikada bir gelen veride neredeyse her bucket tek ölçüm içerebilir; "minutes" seçin.
  • Granularity'yi küçültmeye çalışmak: Yalnızca artırılabilir; ilk seçimi dikkatle yapın.
  • Unique index ile tekrarı engellemeye çalışmak: Desteklenmez; tekrarı uygulama tarafında önleyin.
  • Silmenin anında olmasını beklemek: Bucket bazlı silme nedeniyle eski veri bir süre kalabilir.

Sık Sorulan Sorular

Bir koleksiyonun time series olup olmadığını nasıl anlarım?

db.runCommand( { listCollections: 1, filter: { type: "timeseries" } } ) komutu veritabanındaki tüm time series koleksiyonlarını listeler; çıktıdaki options.timeseries alanında timeField, metaField ve granularity görünür.

Var olan normal koleksiyondaki veriyi time series'e nasıl taşırım?

Önce time series koleksiyonunu oluşturur, sonra veriyi aggregation ile $out aşamasını kullanarak ya da dışa aktarma ve içe aktarma araçlarıyla taşırsınız. Araçlar için MongoDB mongoexport ve mongoimport yazısına bakın.

Time series koleksiyonuna konum verisi koyabilir miyim?

Evet. Belgelere göre time series koleksiyonunun herhangi bir alanında 2dsphere index oluşturabilirsiniz. Sorgularken yakınlık sıralaması için yalnızca $geoNear aşamasını kullanabilirsiniz ve bu aşamanın query alanı time series'te kullanılamaz. Ayrıntılar MongoDB coğrafi sorgular yazısında.

Hangi MongoDB sürümünden itibaren kullanabilirim?

Time series koleksiyonları 5.0 ile geldi; otomatik bileşik index 6.3, özel bucket parametreleri 6.3, ikincil index desteği 6.0 ile eklendi. 9.0 ise depolama biçimini tek namespace'e taşıdı ve yeniden adlandırmaya izin verdi.

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 · TTL index · $group ve accumulator · Veri modelleme · MongoDB 9.0 yenilikleri