Sepanjang Section ini kita memakai string, angka, boolean, dan tanggal tanpa banyak bertanya. Chapter penutup ini memetakan seluruh kosakata tersebut: tipe-tipe BSON yang tersedia, cara menuliskannya di mongosh, dan cara menanyakan tipenya kembali ke server. Pemahaman ini bukan pelengkap — salah tipe angka adalah sumber bug halus paling umum di aplikasi keuangan, dan kita akan membuktikannya lewat eksperimen floating point.

Peta materi Chapter ini:

  • Tabel tipe BSON umum beserta penanda $type dan penulisannya di mongosh.
  • typeof JavaScript versus operator $type BSON — dua pertanyaan yang berbeda.
  • Empat tipe angka: int, long, double, decimal — termasuk bahaya floating point untuk uang.
  • Date, Timestamp, dan BinData.

Peta Tipe BSON #

TipeAlias $typePenulisan di mongoshKegunaan
Double"double"4.5Angka desimal 64-bit (floating point)
String"string""Kopi Gayo"Teks UTF-8
Object"object"{ kota: "Bandung" }Embedded document
Array"array"[ "kopi", "promo" ]Daftar nilai
Binary"binData"BinData(0, "aGVsbG8=")Data biner: file, hash, UUID
ObjectId"objectId"ObjectId()Identifier _id bawaan
Boolean"bool"true / falseLogika benar-salah
Date"date"new Date("2026-10-17")Waktu, presisi milidetik, UTC
Null"null"nullNilai kosong eksplisit
Int32"int"NumberInt(12)Bilangan bulat 32-bit
Timestamp"timestamp"new Timestamp({ t: 1, i: 1 })Khusus internal replikasi (oplog)
Int64"long"NumberLong("270000000")Bilangan bulat 64-bit
Decimal128"decimal"NumberDecimal("45000.00")Desimal presisi tinggi untuk uang
Regex"regex"/^kopi$/iPola pencarian teks
MinKey / MaxKey"minKey" / "maxKey"MinKey() / MaxKey()Penanda batas urutan terkecil/terbesar

Tipe paling khas adalah empat angka dan dua waktu — keduanya dibedah khusus setelah ini. Satu kebiasaan penting sejak awal: angka literal yang bernilai bulat dan muat rentang 32-bit (misalnya 42, bahkan 2.0) disimpan sebagai int; nilai pecahan (misalnya 4.5) dan bilangan di luar rentang 32-bit disimpan sebagai double. Gunakan NumberInt, NumberLong, dan NumberDecimal untuk memilih tipe secara eksplisit, atau new Double(...) untuk memaksa double pada nilai bulat.

typeof JavaScript versus $type BSON #

typeof adalah operator JavaScript — ia melaporkan tipe di sisi shell, bukan tipe BSON yang tersimpan di server:

js
use latihan_tipe
typeof "Budi"
typeof 42
typeof 3.14
typeof ObjectId()

Output yang Dihasilkan:

text
switched to db latihan_tipe
string
number
number
object

Hasilnya string, number, number, dan object: bagi JavaScript, bilangan bulat dan desimal sama-sama number, dan ObjectId hanyalah object. Untuk menanyakan tipe BSON yang sebenarnya, kita mengirim query dengan operator $type ke server. Simpan empat document dengan empat tipe angka berbeda:

js
db.tipe.insertMany([
  { nama: "stok", nilai: NumberInt(12) },
  { nama: "populasi", nilai: NumberLong("270000000") },
  { nama: "harga", nilai: NumberDecimal("45000.00") },
  { nama: "rating", nilai: 4.5 }
])
db.tipe.find()

Output yang Dihasilkan:

text
{
  acknowledged: true,
  insertedIds: {
    '0': ObjectId('6ad3806b14f87baea16eff42'),
    '1': ObjectId('6ad3806b14f87baea16eff43'),
    '2': ObjectId('6ad3806b14f87baea16eff44'),
    '3': ObjectId('6ad3806b14f87baea16eff45')
  }
}
[
  { _id: ObjectId('6ad3806b14f87baea16eff42'), nama: 'stok', nilai: 12 },
  {
    _id: ObjectId('6ad3806b14f87baea16eff43'),
    nama: 'populasi',
    nilai: Long('270000000')
  },
  {
    _id: ObjectId('6ad3806b14f87baea16eff44'),
    nama: 'harga',
    nilai: Decimal128('45000.00')
  },
  {
    _id: ObjectId('6ad3806b14f87baea16eff45'),
    nama: 'rating',
    nilai: 4.5
  }
]

Lalu tanyakan tipenya satu per satu:

js
db.tipe.find({ nilai: { $type: "int" } })
db.tipe.find({ nilai: { $type: "long" } })
db.tipe.find({ nilai: { $type: "decimal" } })
db.tipe.find({ nilai: { $type: "double" } })

Output yang Dihasilkan:

text
[
  { _id: ObjectId('6ad3806b14f87baea16eff42'), nama: 'stok', nilai: 12 }
]
[
  {
    _id: ObjectId('6ad3806b14f87baea16eff43'),
    nama: 'populasi',
    nilai: Long('270000000')
  }
]
[
  {
    _id: ObjectId('6ad3806b14f87baea16eff44'),
    nama: 'harga',
    nilai: Decimal128('45000.00')
  }
]
[
  {
    _id: ObjectId('6ad3806b14f87baea16eff45'),
    nama: 'rating',
    nilai: 4.5
  }
]

Setiap query mengembalikan tepat satu document — keempat angka tersebut memang hidup sebagai empat tipe BSON yang berbeda meski typeof menyebut semuanya number. Perhatikan pula tampilan balikannya: Int32 tampil sebagai angka polos 12, Long tampil sebagai Long('270000000'), dan Decimal128 tampil sebagai Decimal128('45000.00').

Empat Tipe Angka dan Bahayanya bagi Uang #

Constructor di mongosh memetakan tipe BSON secara eksplisit:

js
NumberInt(42)
NumberLong("9007199254740993")
9007199254740993
NumberDecimal("125000.50")

Output yang Dihasilkan:

text
Int32(42)
Long('9007199254740993')
9007199254740992
Decimal128('125000.50')

Bedah hasilnya:

  1. NumberInt(42) menghasilkan Int32(42) — bilangan bulat 32-bit.
  2. NumberLong("9007199254740993") menghasilkan Long('9007199254740993') — bilangan bulat 64-bit yang ditulis sebagai string agar presisinya utuh.
  3. 9007199254740993 tanpa constructor tampil sebagai 9007199254740992 — number JavaScript (double) kehilangan satu digit karena melewati batas aman Number.MAX_SAFE_INTEGER (9007199254740991).
  4. NumberDecimal("125000.50") menghasilkan Decimal128('125000.50') — desimal presisi tinggi.

Untuk uang, double adalah jebakan klasik. Floating point biner tidak bisa merepresentasikan banyak desimal secara persis:

js
0.1 + 0.2
0.1 + 0.2 === 0.3

Output yang Dihasilkan:

text
0.30000000000000004
false

0.1 + 0.2 menghasilkan 0.30000000000000004, dan perbandingannya dengan 0.3 bernilai false. Selisih sepersian miliar ini tampak sepele sampai jutaan transaksi dijumlahkan — lalu pembukuan meleset. Bandingkan penyimpanan dua harga yang sama:

js
db.uang.insertOne({ total: 125000.10 })
db.uang.insertOne({ total: NumberDecimal("125000.10") })
db.uang.find({ total: 125000.10 })

Output yang Dihasilkan:

text
{
  acknowledged: true,
  insertedId: ObjectId('6ad3806c14f87baea16eff46')
}
{
  acknowledged: true,
  insertedId: ObjectId('6ad3806c14f87baea16eff47')
}
[ { _id: ObjectId('6ad3806c14f87baea16eff46'), total: 125000.1 } ]

Document pertama menyimpan 125000.10 sebagai double dan dikembalikan sebagai 125000.1 — angka nol di belakang hilang karena memang tidak pernah tersimpan. Document kedua menyimpan Decimal128('125000.10') dengan kedua digit desimal utuh, dan query di atas hanya cocok dengan document pertama karena 125000.10 (double) dan NumberDecimal("125000.10") adalah dua nilai yang berbeda tipenya.

Date, Timestamp, dan BinData #

Waktu dalam BSON punya dua bentuk. Date menyimpan milidetik sejak Unix epoch dan dipakai untuk data aplikasi:

js
new Date("2026-10-17T09:30:00Z")
ISODate("2026-10-17")

Output yang Dihasilkan:

text
ISODate('2026-10-17T09:30:00.000Z')
ISODate('2026-10-17T00:00:00.000Z')

Kedua bentuk menghasilkan ISODate — new Date() adalah constructor JavaScript standar, sedangkan ISODate() adalah helper mongosh yang lebih ringkas. Zona waktu yang tercetak adalah UTC; konversi ke waktu lokal menjadi tanggung jawab aplikasi.

Timestamp adalah tipe berbeda yang dipakai internal replikasi — setiap entri oplog diberi Timestamp berisi detik plus penghitung urutan operasi:

js
new Timestamp({ t: 1792243658, i: 1 })

Output yang Dihasilkan:

text
Timestamp({ t: 1792243658, i: 1 })

Kita hampir tidak pernah menulis Timestamp sendiri; cukup kenali bentuknya saat membaca operationTime atau oplog, dan gunakan Date untuk seluruh kebutuhan aplikasi.

Terakhir, BinData menyimpan byte mentah — file, hash, atau UUID:

js
BinData(0, "aGVsbG8=")

Output yang Dihasilkan:

text
Binary.createFromBase64('aGVsbG8=', 0)

Argumen pertama adalah subtype (0 berarti data biner generik) dan argumen kedua adalah data terenkode base64 — "aGVsbG8=" adalah hasil enkoding teks hello. Ukuran data biner dalam satu document tetap tunduk pada batas 16 MB; untuk file besar tetap berlaku saran Chapter Documents dan BSON: pecah atau gunakan GridFS.

Sebagai penutup, bersihkan database latihan:

js
db.dropDatabase()

Output yang Dihasilkan:

text
{ ok: 1, dropped: 'latihan_tipe' }

Rangkuman #

  • BSON mengenal tipe kaya: empat angka (int, long, double, decimal), Date, Timestamp, BinData, ObjectId, dan lainnya — lengkap dengan alias $type.
  • typeof melaporkan tipe JavaScript di shell; operator $type menanyakan tipe BSON sebenarnya ke server.
  • Angka literal di mongosh: nilai bulat yang muat 32-bit tersimpan sebagai int, pecahan dan bilangan di luar rentang tersimpan double; gunakan NumberInt, NumberLong, dan NumberDecimal untuk memilih tipe eksplisit.
  • Floating point tidak persis untuk desimal (0.1 + 0.2 !== 0.3); untuk uang pakai NumberDecimal atau sen sebagai NumberLong.
  • Date untuk aplikasi, Timestamp untuk internal replikasi, BinData untuk byte mentah.

Kosakata lengkap BSON di tangan, kita siap masuk Section berikutnya: mengoperasikan mongosh secara mahir — dari memilih database sampai helper yang mempercepat kerja sehari-hari.