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
$typedan penulisannya di mongosh. typeofJavaScript versus operator$typeBSON — dua pertanyaan yang berbeda.- Empat tipe angka:
int,long,double,decimal— termasuk bahaya floating point untuk uang. Date,Timestamp, danBinData.
Peta Tipe BSON #
| Tipe | Alias $type | Penulisan di mongosh | Kegunaan |
|---|---|---|---|
| Double | "double" | 4.5 | Angka 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 / false | Logika benar-salah |
| Date | "date" | new Date("2026-10-17") | Waktu, presisi milidetik, UTC |
| Null | "null" | null | Nilai 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$/i | Pola 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:
use latihan_tipe
typeof "Budi"
typeof 42
typeof 3.14
typeof ObjectId()Output yang Dihasilkan:
switched to db latihan_tipe
string
number
number
objectHasilnya 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:
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:
{
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:
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:
[
{ _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:
NumberInt(42)
NumberLong("9007199254740993")
9007199254740993
NumberDecimal("125000.50")Output yang Dihasilkan:
Int32(42)
Long('9007199254740993')
9007199254740992
Decimal128('125000.50')Bedah hasilnya:
NumberInt(42)menghasilkanInt32(42)— bilangan bulat 32-bit.NumberLong("9007199254740993")menghasilkanLong('9007199254740993')— bilangan bulat 64-bit yang ditulis sebagai string agar presisinya utuh.9007199254740993tanpa constructor tampil sebagai9007199254740992— number JavaScript (double) kehilangan satu digit karena melewati batas amanNumber.MAX_SAFE_INTEGER(9007199254740991).NumberDecimal("125000.50")menghasilkanDecimal128('125000.50')— desimal presisi tinggi.
Untuk uang, double adalah jebakan klasik. Floating point biner tidak bisa merepresentasikan banyak desimal secara persis:
0.1 + 0.2
0.1 + 0.2 === 0.3Output yang Dihasilkan:
0.30000000000000004
false0.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:
db.uang.insertOne({ total: 125000.10 })
db.uang.insertOne({ total: NumberDecimal("125000.10") })
db.uang.find({ total: 125000.10 })Output yang Dihasilkan:
{
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:
new Date("2026-10-17T09:30:00Z")
ISODate("2026-10-17")Output yang Dihasilkan:
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:
new Timestamp({ t: 1792243658, i: 1 })Output yang Dihasilkan:
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:
BinData(0, "aGVsbG8=")Output yang Dihasilkan:
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:
db.dropDatabase()Output yang Dihasilkan:
{ 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. typeofmelaporkan tipe JavaScript di shell; operator$typemenanyakan tipe BSON sebenarnya ke server.- Angka literal di mongosh: nilai bulat yang muat 32-bit tersimpan sebagai
int, pecahan dan bilangan di luar rentang tersimpandouble; gunakanNumberInt,NumberLong, danNumberDecimaluntuk memilih tipe eksplisit. - Floating point tidak persis untuk desimal (
0.1 + 0.2 !== 0.3); untuk uang pakaiNumberDecimalatau sen sebagaiNumberLong. Dateuntuk aplikasi,Timestampuntuk internal replikasi,BinDatauntuk 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.