Verifikasi instalasi di Section sebelumnya sudah membuktikan siklus tulis-baca bekerja. Sekarang kita masuk ke pertanyaan yang lebih mendasar: ke mana persisnya data itu tersimpan? MongoDB menyusun penyimpanan dalam hierarki yang sederhana — server menampung database, database menampung collection, dan collection menampung document — dan hampir semua perintah mongosh bergantung pada posisi kita di dalam hierarki tersebut.

Peta materi Chapter ini:

  • Hierarki penyimpanan dan konsep namespace <database>.<collection>.
  • Pembuatan lazy: database dan collection baru hanya tercipta saat data pertama ditulis.
  • Pembuatan eksplisit dengan db.createCollection(), termasuk opsi capped.
  • Aturan penamaan untuk database dan collection beserta galat yang muncul jika dilanggar.

Hierarki Penyimpanan dan Namespace #

Satu proses mongod (satu deployment) bisa menampung banyak database yang saling terpisah, dan setiap database bisa memiliki banyak collection. Ilustrasi berikut memakai nama yang akan kita gunakan sepanjang Chapter:

Gabungan nama database dan nama collection membentuk namespace lengkap sebuah collection, ditulis dengan format <database>.<collection> — misalnya latihan_toko.produk. Namespace inilah identitas collection di level server, dan panjangnya dibatasi 255 byte untuk collection biasa (235 byte untuk collection yang di-shard). Identitas tersebut bisa kita lihat langsung lewat db.<collection>.stats().ns begitu collection pertama kita dibuat nanti.

Membuat Database dengan use #

Berbeda dengan database relasional, MongoDB tidak punya perintah khusus “buat database”. Kita hanya berpindah konteks dengan use, dan database baru belum tercipta apa-apa:

js
use latihan_toko

Output yang Dihasilkan:

text
switched to db latihan_toko

Shell mengonfirmasi perpindahan konteks, tetapi belum ada satu byte pun yang ditulis ke disk. Buktikan dengan memeriksa isi server dan isi database aktif:

js
show dbs
db.getCollectionNames()

Output yang Dihasilkan:

text
admin    80.00 KiB
config  408.00 KiB
local   564.00 KiB
[]

Daftar database hanya menampilkan admin, config, dan local — database bawaan yang sudah kita kenal di Chapter Verifikasi Instalasi — dan latihan_toko belum terdaftar. Ukuran config dan local berubah mengikuti aktivitas internal server, jadi nilai KiB di mesin kita boleh sedikit berbeda. Array kosong dari db.getCollectionNames() juga menegaskan bahwa database aktif belum memiliki satu collection pun. Inilah yang disebut lazy creation: use hanya mengalihkan konteks, bukan membuat struktur penyimpanan.

Database dan collection benar-benar tercipta saat operasi tulis pertama menyentuhnya:

js
db.stok.insertOne({ nama: "Kopi Gayo", jumlah: 40 })

Output yang Dihasilkan:

text
{
  acknowledged: true,
  insertedId: ObjectId('6ad3806d1a3d37e015bb2e41')
}

Satu insertOne ke collection stok sekaligus membuat collection stok dan database latihan_toko. Periksa kembali:

js
show dbs
show collections

Output yang Dihasilkan:

text
admin          80.00 KiB
config        408.00 KiB
latihan_toko    8.00 KiB
local         564.00 KiB
stok

latihan_toko kini muncul di daftar database dengan ukuran awal 8 KiB, dan stok terdaftar sebagai satu-satunya collection di dalamnya. Perhatikan bahwa stok tercipta tanpa perintah pembuatan apa pun — MongoDB membuat collection secara implisit begitu document pertama ditulis ke dalamnya.

Membuat Collection Secara Eksplisit #

Pembuatan implisit memang praktis, tetapi kita kadang perlu membuat collection lebih dulu — misalnya untuk menetapkan opsi khusus. Untuk itu ada db.createCollection():

js
db.createCollection("produk")

Output yang Dihasilkan:

text
{ ok: 1 }

Balasan { ok: 1 } menandakan collection produk berhasil dibuat dan langsung tersedia meski belum berisi document apa pun. Sekarang kita bisa memeriksa namespace lengkapnya:

js
db.produk.stats().ns

Output yang Dihasilkan:

text
latihan_toko.produk

Bandingkan dengan stok yang baru muncul setelah insert — keduanya kini terdaftar bersama:

js
db.getCollectionNames()

Output yang Dihasilkan:

text
[ 'produk', 'stok' ]

Kekuatan utama db.createCollection() ada di parameter opsi keduanya. Contoh paling dikenal adalah capped collection — collection berukuran tetap yang secara otomatis membuang document tertua saat kapasitasnya penuh, cocok untuk log dan data berumur pendek:

js
db.createCollection("log", { capped: true, size: 4096, max: 2 })

Output yang Dihasilkan:

text
{ ok: 1 }

Mari kita bedah opsi tersebut:

  1. capped: true mengaktifkan mode collection tetap; tanpa opsi ini, collection tumbuh tanpa batas.
  2. size: 4096 menetapkan batas total 4096 byte. Nilai size wajib ada saat capped aktif.
  3. max: 2 menetapkan batas jumlah document. Saat salah satu batas tercapai, document tertua dihapus otomatis untuk memberi ruang.

Opsi yang tersimpan bisa kita lihat kembali lewat db.getCollectionInfos():

js
db.getCollectionInfos({ name: "log" })

Output yang Dihasilkan:

text
[
  {
    name: 'log',
    type: 'collection',
    options: { capped: true, size: 4096, max: 2 },
    info: { readOnly: false, uuid: UUID('a221a290-41d7-446b-8759-ddcc0ae9375b') },
    idIndex: { v: 2, key: { _id: 1 }, name: '_id_' }
  }
]

Perilaku capped bisa dibuktikan langsung. Masukkan tiga document ke dalam log yang dibatasi max: 2, lalu baca isinya:

js
db.log.insertOne({ pesan: "log ke-1" })
db.log.insertOne({ pesan: "log ke-2" })
db.log.insertOne({ pesan: "log ke-3" })
db.log.find()

Output yang Dihasilkan:

text
{
  acknowledged: true,
  insertedId: ObjectId('6ad3806e1a3d37e015bb2e42')
}
{
  acknowledged: true,
  insertedId: ObjectId('6ad3806e1a3d37e015bb2e43')
}
{
  acknowledged: true,
  insertedId: ObjectId('6ad3806e1a3d37e015bb2e44')
}
[
  { _id: ObjectId('6ad3806e1a3d37e015bb2e43'), pesan: 'log ke-2' },
  { _id: ObjectId('6ad3806e1a3d37e015bb2e44'), pesan: 'log ke-3' }
]

Hanya log ke-2 dan log ke-3 yang tersisa — document pertama terhapus otomatis begitu document ketiga masuk. Kita juga bisa memastikan status capped kapan saja:

js
db.log.isCapped()

Output yang Dihasilkan:

text
true

Aturan Penamaan Database dan Collection #

Nama adalah kontrak: sekali data tersimpan, nama database dan collection menjadi bagian dari namespace yang dirujuk semua aplikasi. MongoDB menerapkan aturan berbeda untuk keduanya:

AspekDatabaseCollection
Nama kosongDitolakDitolak
Karakter terlarang (Linux)/ \ . " $ dan karakter null$ dan karakter null
Karakter terlarang (Windows)Ditambah * < > : `?`
Panjang maksimumKurang dari 64 byteNamespace total ≤ 255 byte
Awalan terlarang—system. (dipesan untuk internal)
KapitalisasiCase-sensitive; jangan andalkan huruf besar-kecil untuk membedakan namaCase-sensitive

Dua catatan penting dari tabel tersebut. Pertama, batas karakter Windows lebih ketat karena sistem berkasnya; agar aman lintas platform, hindari semua karakter terlarang dan gunakan huruf kecil. Kedua, awalan system. dipesan untuk collection internal MongoDB — membuat collection dengan awalan tersebut akan ditolak.

Pelanggaran aturan langsung terlihat sebagai galat. Coba dua nama yang melanggar:

js
db.createCollection("produk$stok")
db.getSiblingDB("toko baru").createCollection("x")

Output yang Dihasilkan:

text
Uncaught 
MongoServerError[InvalidNamespace]: Invalid collection name: produk$stok
Uncaught 
MongoshInvalidInputError: [COMMON-10001] Invalid database name: toko baru

Server menolak produk$stok karena nama collection tidak boleh mengandung $, sedangkan mongosh menolak nama database toko baru lebih dulu di sisi klien karena mengandung spasi. Untuk nama collection yang diawali angka atau memakai tanda hubung, akses dengan kurung siku atau db.getCollection() agar mongosh tidak salah mengurai — misalnya db["2024-orders"] atau db.getCollection("log-aktif").

Rangkuman #

KegiatanPerintahCatatan
Berpindah databaseuse latihan_tokoTidak membuat apa pun
Melihat daftar databaseshow dbsDatabase baru muncul setelah tulis pertama
Melihat collectionshow collections / db.getCollectionNames()—
Membuat collection implisitdb.stok.insertOne({...})Collection + database tercipta otomatis
Membuat collection eksplisitdb.createCollection("log", {...})Bisa membawa opsi
Collection berukuran tetap{ capped: true, size, max }Document tertua terhapus otomatis
Namespacedb.produk.stats().nslatihan_toko.produk, maksimum 255 byte

Sebagai penutup, hapus database latihan ini dan pastikan server kembali bersih:

js
db.dropDatabase()
show dbs

Output yang Dihasilkan:

text
{ ok: 1, dropped: 'latihan_toko' }
admin    80.00 KiB
config  408.00 KiB
local   564.00 KiB

Database, collection, dan document kini punya tempat yang jelas dalam peta mental kita. Chapter berikutnya membedah isi collection itu sendiri: document dan format biner BSON yang menyimpannya.