BMKG memasang sensor cuaca di puluhan kota: Jakarta mengirim suhu dan kelembapan setiap menit, Bandung setiap lima menit. Dalam sehari saja, satu sensor menghasilkan 1.440 pembacaan; seratus sensor menghasilkan 144.000 document per hari, dan datanya terus bertambah tanpa henti. Data seperti ini punya pola akses yang sangat khas — ditulis terus-menerus, dibaca lewat agregasi rentang waktu, lalu makin lama makin jarang dibaca. Chapter ini memetakan karakteristik tersebut, use case nyata di berbagai industri, dan alasan collection biasa menjadi pilihan yang mahal untuk pola seperti ini.

Karakteristik Data Time Series #

Data time series adalah urutan titik data yang maknanya muncul dari perubahan sepanjang waktu. Empat ciri berikut membedakannya dari data operasional biasa:

  • Tulis banyak, tulis berurutan — data datang sebagai insert yang menempel di ujung deret, bukan update terhadap baris lama. Setiap pembacaan sensor adalah document baru.
  • Baca lewat agregasi — pertanyaan yang diajukan hampir selalu berbentuk “rata-rata suhu Jakarta jam 02:00 tadi” atau “suhu tertinggi minggu ini”, bukan “ambil satu document”.
  • Usia data memengaruhi nilai — data 6 jam terakhir dibaca setiap detik untuk dasbor, data 6 bulan terakhir cukup untuk laporan mingguan, data 3 tahun lalu boleh dihapus demi penghematan disk.
  • Volume tinggi dan monoton naik — jumlah document hanya bertambah; tanpa kebijakan retensi, storage tumbuh tanpa batas.

Ciri keempat itu yang paling sering mengejutkan tim operasional: aplikasi CRUD biasa menambah dan menghapus data seimbang, sedangkan pipeline sensor hanya menambah.

Use Case di Lapangan #

Pola yang sama berulang di banyak industri. Komponen penyusunnya selalu serupa: satu field waktu, satu identitas sumber data (metadata), dan sejumlah metrik numerik.

DomainMetadata (identitas seri)Metrik
IoT dan sensor cuacasensor_id, kota, tipe sensorsuhu, kelembapan, tekanan udara
Monitoring serverhost, region, nama serviceCPU, memori, latensi, jumlah request
Keuangankode saham, bursaharga, volume transaksi
Analitik webID halaman, ID kampanyejumlah kunjungan, durasi sesi

Di domain cuaca, identitas serinya adalah pasangan sensor_id dan kota; metriknya adalah suhu dan kelembapan. Struktur ini nanti menjadi dasar pemilihan metaField di Chapter Desain Schema Time Series.

Kenapa Collection Biasa Menjadi Mahal #

Kita buktikan sendiri pola masalahnya dengan collection reguler. Berikut 12 pembacaan dari tiga sensor, disimpan persis seperti data CRUD biasa:

js
use latihan_timeseries
db.dropDatabase()
db.pembacaan_reguler.insertMany([
  { waktu: ISODate("2026-12-10T02:00:00Z"), sensor_id: "JKT-01", kota: "Jakarta", suhu: 27.4, kelembapan: 78 },
  { waktu: ISODate("2026-12-10T02:01:00Z"), sensor_id: "JKT-01", kota: "Jakarta", suhu: 27.6, kelembapan: 77 },
  { waktu: ISODate("2026-12-10T02:02:00Z"), sensor_id: "JKT-01", kota: "Jakarta", suhu: 27.9, kelembapan: 75 },
  { waktu: ISODate("2026-12-10T02:03:00Z"), sensor_id: "JKT-01", kota: "Jakarta", suhu: 28.1, kelembapan: 74 },
  { waktu: ISODate("2026-12-10T02:00:00Z"), sensor_id: "BDG-07", kota: "Bandung", suhu: 22.1, kelembapan: 85 },
  { waktu: ISODate("2026-12-10T02:01:00Z"), sensor_id: "BDG-07", kota: "Bandung", suhu: 22.3, kelembapan: 84 },
  { waktu: ISODate("2026-12-10T02:02:00Z"), sensor_id: "BDG-07", kota: "Bandung", suhu: 22.2, kelembapan: 84 },
  { waktu: ISODate("2026-12-10T02:03:00Z"), sensor_id: "BDG-07", kota: "Bandung", suhu: 22.4, kelembapan: 83 },
  { waktu: ISODate("2026-12-10T02:00:00Z"), sensor_id: "SBY-12", kota: "Surabaya", suhu: 30.2, kelembapan: 68 },
  { waktu: ISODate("2026-12-10T02:01:00Z"), sensor_id: "SBY-12", kota: "Surabaya", suhu: 30.4, kelembapan: 67 },
  { waktu: ISODate("2026-12-10T02:02:00Z"), sensor_id: "SBY-12", kota: "Surabaya", suhu: 30.6, kelembapan: 66 },
  { waktu: ISODate("2026-12-10T02:03:00Z"), sensor_id: "SBY-12", kota: "Surabaya", suhu: 30.5, kelembapan: 66 }
])
db.pembacaan_reguler.getIndexes()

Output yang Dihasilkan:

text
switched to db latihan_timeseries
{ ok: 1, dropped: 'latihan_timeseries' }
{
  acknowledged: true,
  insertedIds: {
    '0': ObjectId('6ad3dfb49873997bc775990e'),
    '1': ObjectId('6ad3dfb49873997bc775990f'),
    '2': ObjectId('6ad3dfb49873997bc7759910'),
    '3': ObjectId('6ad3dfb49873997bc7759911'),
    '4': ObjectId('6ad3dfb49873997bc7759912'),
    '5': ObjectId('6ad3dfb49873997bc7759913'),
    '6': ObjectId('6ad3dfb49873997bc7759914'),
    '7': ObjectId('6ad3dfb49873997bc7759915'),
    '8': ObjectId('6ad3dfb49873997bc7759916'),
    '9': ObjectId('6ad3dfb49873997bc7759917'),
    '10': ObjectId('6ad3dfb49873997bc7759918'),
    '11': ObjectId('6ad3dfb49873997bc7759919')
  }
}
[
  {
    v: 2,
    key: { _id: 1 },
    name: '_id_',
    collation: { locale: 'simple' }
  }
]

Perhatikan dua hal dari keluaran di atas. Pertama, setiap document membawa _id ObjectId plus entry index _id_ — overhead yang sama sekali tidak dipakai, karena tidak ada yang pernah mencari pembacaan sensor berdasarkan ObjectId acak. Kedua, pasangan sensor_id dan kota diulang dua belas kali; pada skala jutaan pembacaan per hari, pengulangan ini menggerus storage dan cache jauh lebih besar daripada nilainya sendiri. Kita sudah mengukur efek serupa di Chapter Bucket Pattern — 12 document mentah memakan 836 byte untuk data yang muat dalam 336 byte.

Query analisisnya pun harus menyisir semua document itu. Pola baca yang khas — rata-rata suhu per sensor — terlihat seperti ini:

js
db.pembacaan_reguler.aggregate([ { $group: { _id: "$sensor_id", rataSuhu: { $avg: "$suhu" }, pembacaan: { $sum: 1 } } }, { $sort: { _id: 1 } } ])

Output yang Dihasilkan:

text
[
  { _id: 'BDG-07', rataSuhu: 22.25, pembacaan: 4 },
  { _id: 'JKT-01', rataSuhu: 27.75, pembacaan: 4 },
  { _id: 'SBY-12', rataSuhu: 30.425, pembacaan: 4 }
]

Pipeline ini benar, tetapi di balik layar server harus membongkar 12 document penuh hanya untuk menjumlahkan field suhu. Pada jutaan document, pola simpan-satu-pembacaan-per-document memaksa server membaca blok disk yang penuh data yang tidak relevan untuk menjawab satu pertanyaan agregasi.

Solusi: Bucket Otomatis #

Time series collections memindahkan pekerjaan pengelompokan ini ke dalam server. Kita tetap menyisipkan satu document per pembacaan, tetapi MongoDB mengelompokkannya otomatis ke dalam bucket — document internal berformat kolom yang menampung banyak pembacaan dari sumber yang sama pada rentang waktu berdekatan:

Setiap bucket menyimpan metadata seri sekali, lalu metrik dalam format kolom terkompresi — persis prinsip Bucket Pattern, tetapi dikelola server sejak MongoDB 5.0. Index yang dibutuhkan query rentang waktu dibangun di tingkat bucket, jauh lebih kecil daripada index per pembacaan. Bagian selanjutnya dari section ini membahas cara membuatnya, mendesain schemanya, mengindeksnya, sampai membandingkannya dengan capped collection dan view.

Rangkuman #

  • Data time series ditulis terus-menerus, dibaca lewat agregasi rentang waktu, dan volumenya tumbuh monoton — kombinasi yang membuat pola simpan CRUD biasa menjadi mahal.
  • Collection reguler membayar overhead _id dan index per pembacaan, plus pengulangan metadata pada setiap document.
  • Bucket internal menyimpan metadata seri sekali dan metrik dalam format kolom terkompresi, menekan storage dan mempercepat agregasi.
  • Use case utamanya: sensor IoT dan cuaca, monitoring server, data keuangan, dan analitik web.