Chapter BSON Types memetakan seluruh tipe yang bisa disimpan BSON — empat tipe angka, Date, ObjectId, array, hingga BinData. Sekarang kita belajar memaksa server menolak tipe yang salah lewat kata kunci bsonType. Ini penjaga pintu paling dasar sekaligus paling sering dijumpai: sebagian besar data rusak bermula dari field yang tipenya tidak sesuai harapan.
“number” versus Tipe Angka Spesifik #
bsonType mengenal dua tingkat ketat untuk angka. Nilai "number" menerima semua tipe angka BSON, sedangkan "int", "long", "double", dan "decimal" menuntut tipe spesifik tersebut:
Nilai bsonType | Yang diterima | Kapan dipakai |
|---|---|---|
"number" | double, int, long, decimal | Field angka umum |
"double" | Hanya double 64-bit | Nilai hasil pengukuran |
"int" | Hanya Int32 | Bilangan bulat kecil: stok, jumlah |
"long" | Hanya Int64 | Bilangan bulat besar |
"decimal" | Hanya Decimal128 | Uang presisi tinggi |
Ingat perilaku angka literal di mongosh dari Chapter BSON Types: bilangan yang bernilai bulat dan muat rentang Int32 tersimpan sebagai int — termasuk yang ditulis dengan titik desimal seperti 2.0 — sedangkan nilai pecahan seperti 0.25 dan bilangan di luar rentang Int32 tersimpan sebagai double. Perilaku ini menentukan lolos atau tidaknya sebuah insert. Kita buat collection dengan campuran tipe ketat:
use latihan_validasi
db.produk.drop()
db.createCollection("produk", { validator: { $jsonSchema: {
bsonType: "object",
required: ["nama", "sku", "harga", "stok"],
properties: {
_id: { bsonType: "objectId" },
nama: { bsonType: "string" },
sku: { bsonType: "string" },
harga: { bsonType: "number", minimum: 0 },
stok: { bsonType: "int", minimum: 0 },
berat: { bsonType: "double", minimum: 0 },
tanggal_ditambahkan: { bsonType: "date" },
aktif: { bsonType: "bool" },
tag: { bsonType: "array" },
deskripsi: { bsonType: ["string", "null"], maxLength: 200 }
}
} } })
db.produk.insertOne({
nama: "Kopi Gayo 250g",
sku: "MIN-001",
harga: 85000,
stok: 40,
berat: 0.25,
tanggal_ditambahkan: new Date("2026-01-10"),
aktif: true,
tag: ["kopi", "arabika"],
deskripsi: null
})Output yang Dihasilkan:
switched to db latihan_validasi
true
{ ok: 1 }
{
acknowledged: true,
insertedId: ObjectId('6ad3901510c4756be30e78cf')
}stok: 40 lolos karena literal tersebut memang int; berat: 0.25 lolos karena nilai pecahan menjadi double. Sekarang kita balik kadarnya — stok diberi desimal, berat diberi bilangan bulat:
db.produk.insertOne({ nama: "Teh Melati 100g", sku: "MIN-002", harga: 15000, stok: 25.5 })
db.produk.insertOne({ nama: "Teh Melati 100g", sku: "MIN-002", harga: 15000, stok: 25, berat: 250 })Output yang Dihasilkan:
Uncaught:
MongoServerError: Document failed validation
Additional information: {
failingDocumentId: ObjectId('6ad3901510c4756be30e78d0'),
details: {
operatorName: '$jsonSchema',
schemaRulesNotSatisfied: [
{
operatorName: 'properties',
propertiesNotSatisfied: [
{
propertyName: 'stok',
details: [
{
operatorName: 'bsonType',
specifiedAs: { bsonType: 'int' },
reason: 'type did not match',
consideredValue: 25.5,
consideredType: 'double'
}
]
}
]
}
]
}
}
Uncaught:
MongoServerError: Document failed validation
Additional information: {
failingDocumentId: ObjectId('6ad3901510c4756be30e78d1'),
details: {
operatorName: '$jsonSchema',
schemaRulesNotSatisfied: [
{
operatorName: 'properties',
propertiesNotSatisfied: [
{
propertyName: 'berat',
details: [
{
operatorName: 'bsonType',
specifiedAs: { bsonType: 'double' },
reason: 'type did not match',
consideredValue: 250,
consideredType: 'int'
}
]
}
]
}
]
}
}Kedua insert ditolak dengan alasan yang sama-sama type did not match: 25.5 adalah double sehingga gagal di stok yang menuntut int, dan 250 adalah int sehingga gagal di berat yang menuntut double. Pesan galatnya menyebut consideredType — tipe aktual nilai yang kita kirim — sehingga penyebabnya langsung terlihat.
“number” Menerima Semua Tipe Angka #
Berbeda dengan dua field ketat tadi, harga bertipe "number" menerima keempat tipe angka BSON sekaligus. Empat insert berikut semuanya lolos:
db.produk.insertOne({ nama: "Teh Melati 100g", sku: "MIN-002", harga: 15000, stok: 25 })
db.produk.insertOne({ nama: "Gula Pasir 1kg", sku: "MAK-001", harga: NumberLong("15000"), stok: 25 })
db.produk.insertOne({ nama: "Susu UHT 1L", sku: "MIN-003", harga: NumberDecimal("19500.00"), stok: 25 })
db.produk.insertOne({ nama: "Kopi Tubruk 200g", sku: "MIN-004", harga: 12000.5, stok: 25 })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: ObjectId('6ad3901510c4756be30e78d2')
}
{
acknowledged: true,
insertedId: ObjectId('6ad3901510c4756be30e78d3')
}
{
acknowledged: true,
insertedId: ObjectId('6ad3901510c4756be30e78d4')
}
{
acknowledged: true,
insertedId: ObjectId('6ad3901510c4756be30e78d5')
}Empat nilai harga di atas masing-masing tersimpan sebagai int, long, decimal, dan double — dan semuanya sah bagi "number". Aturan praktisnya: pakai "number" saat aplikasi menulis lewat banyak jalur dengan tipe angka berbeda; pakai tipe spesifik saat konsistensi tipe benar-benar dibutuhkan, misalnya "decimal" untuk kolom uang.
Tipe Non-angka #
Sisanya langsung menyebut namanya: "string", "bool", "date", "objectId", "array", dan "object". Dua kasus yang paling sering terjadi: tanggal yang dikirim sebagai string dari aplikasi, dan _id custom yang bukan ObjectId:
db.produk.insertOne({ nama: "Teh Melati 100g", sku: "MIN-002", harga: 15000, stok: 25, tanggal_ditambahkan: "2026-02-01" })
db.produk.insertOne({ _id: "PRODUK-001", nama: "Teh Melati 100g", sku: "MIN-002", harga: 15000, stok: 25 })Output yang Dihasilkan:
Uncaught:
MongoServerError: Document failed validation
Additional information: {
failingDocumentId: ObjectId('6ad3901510c4756be30e78d6'),
details: {
operatorName: '$jsonSchema',
schemaRulesNotSatisfied: [
{
operatorName: 'properties',
propertiesNotSatisfied: [
{
propertyName: 'tanggal_ditambahkan',
details: [
{
operatorName: 'bsonType',
specifiedAs: { bsonType: 'date' },
reason: 'type did not match',
consideredValue: '2026-02-01',
consideredType: 'string'
}
]
}
]
}
]
}
}
Uncaught:
MongoServerError: Document failed validation
Additional information: {
failingDocumentId: 'PRODUK-001',
details: {
operatorName: '$jsonSchema',
schemaRulesNotSatisfied: [
{
operatorName: 'properties',
propertiesNotSatisfied: [
{
propertyName: '_id',
details: [
{
operatorName: 'bsonType',
specifiedAs: { bsonType: 'objectId' },
reason: 'type did not match',
consideredValue: 'PRODUK-001',
consideredType: 'string'
}
]
}
]
}
]
}
}Insert pertama gagal karena "2026-02-01" bertipe string, bukan date — new Date("2026-02-01") barulah lolos. Insert kedua gagal karena _id: "PRODUK-001" bertipe string padahal validator menuntut objectId. Perhatikan failingDocumentId pada galat kedua: nilainya persis string 'PRODUK-001' yang kita kirim.
Tipe Ganda: string atau null #
bsonType juga menerima array tipe — nilai dianggap sah bila cocok dengan salah satunya. Pola paling umum adalah ["string", "null"] untuk field opsional yang boleh “ada tapi kosong”. Insert pertama kita sudah membuktikan deskripsi: null lolos; sekarang kita kirim nilai yang bukan string dan bukan null, plus boolean berupa teks:
db.produk.insertOne({ nama: "Teh Melati 100g", sku: "MIN-002", harga: 15000, stok: 25, deskripsi: 42 })
db.produk.insertOne({ nama: "Teh Melati 100g", sku: "MIN-002", harga: 15000, stok: 25, aktif: "ya" })Output yang Dihasilkan:
Uncaught:
MongoServerError: Document failed validation
Additional information: {
failingDocumentId: ObjectId('6ad3901510c4756be30e78d7'),
details: {
operatorName: '$jsonSchema',
schemaRulesNotSatisfied: [
{
operatorName: 'properties',
propertiesNotSatisfied: [
{
propertyName: 'deskripsi',
details: [
{
operatorName: 'bsonType',
specifiedAs: { bsonType: [ 'string', 'null' ] },
reason: 'type did not match',
consideredValue: 42,
consideredType: 'int'
}
]
}
]
}
]
}
}
Uncaught:
MongoServerError: Document failed validation
Additional information: {
failingDocumentId: ObjectId('6ad3901510c4756be30e78d8'),
details: {
operatorName: '$jsonSchema',
schemaRulesNotSatisfied: [
{
operatorName: 'properties',
propertiesNotSatisfied: [
{
propertyName: 'aktif',
details: [
{
operatorName: 'bsonType',
specifiedAs: { bsonType: 'bool' },
reason: 'type did not match',
consideredValue: 'ya',
consideredType: 'string'
}
]
}
]
}
]
}
}Bedah dua hasil di atas:
deskripsi: 42ditolak —42bukanstringdan bukannull.aktif: "ya"ditolak —boolhanya menerimatrueataufalse, string tidak pernah otomatis dikonversi.
Bersihkan database latihan:
db.dropDatabase()Output yang Dihasilkan:
{ ok: 1, dropped: 'latihan_validasi' }Rangkuman #
"number"menerimadouble,int,long, dandecimalsekaligus;"int","long","double","decimal"menuntut tipe persisnya.- Literal di mongosh: bilangan bulat muat Int32 menjadi
int, berkoma menjadidouble— ini menentukan lolos tidaknya validator ketat. - Tipe non-angka ditulis langsung:
"string","bool","date","objectId","array","object". - Pesan galat
type did not matchmenyertakanconsideredType— tipe aktual nilai yang dikirim. bsonTypemenerima array seperti["string", "null"]untuk field opsional yang boleh kosong.
Materi selanjutnya membahas kata kunci yang paling sering dipakai bersama bsonType: required — dan jebakan null yang menyertainya.