Driver mentah menempatkan tanggung jawab bentuk dokumen sepenuhnya pada kode aplikasi, sehingga setiap fungsi yang menyimpan data menjaga sendiri field wajib dan tipe nilainya. Object-Document Mapper (ODM), yaitu pustaka yang membungkus driver dengan definisi schema dan model, memindahkan tanggung jawab itu ke satu tempat. Topik ini membahas posisi ODM di antara driver mentah dan skema aplikasi, menggunakan Mongoose sebagai contoh yang lazim pada ekosistem Node.js, serta membandingkannya dengan pola validasi manual yang dapat dijalankan pada lingkungan latihan ini. Setelah mengikuti topik ini, keputusan menggunakan ODM atau tidak dapat diambil berdasarkan konsekuensi konkretnya, bukan berdasarkan kebiasaan.
Lapisan yang ditambahkan ODM#
ODM berdiri di atas driver, bukan menggantikannya. Pustaka ODM menggunakan driver resmi untuk setiap operasi jaringan, lalu menambahkan hal yang tidak dimiliki driver, yaitu definisi schema dalam kode, konversi tipe otomatis (casting), dan validasi sebelum tulisan dikirim. Definisi schema menetapkan field apa saja yang sah pada sebuah model, tipe nilainya, dan aturan tambahan seperti nilai wajib atau rentang angka. Konversi tipe menyeragamkan nilai yang masuk, misalnya string angka menjadi bilangan, sebelum dokumen sampai ke server.
Lapisan-lapisan itu mengubah cara aplikasi berbicara dengan MongoDB. Alih-alih memanggil collection.insertOne() dengan dokumen bebas, aplikasi memanggil metode pada model dan menerima objek model sebagai hasilnya. Field yang tidak terdaftar pada schema dibuang, nilai yang belum diisi diberi nilai bawaan, dan pelanggaran aturan mengangkat error sebelum jaringan disentuh. ODM juga menyediakan hook, yaitu fungsi yang dijalankan otomatis sebelum atau sesudah operasi tertentu, misalnya untuk mencatat waktu perubahan pada field tersendiri. Karena aturannya terpusat pada satu definisi, perubahan bentuk dokumen cukup dilakukan di satu tempat, dan bentuk data yang sah dapat ditelusuri tanpa membuka banyak berkas aplikasi.
Schema dan model pada Mongoose#
Mongoose dipasang melalui npm install mongoose, dan package itu tidak tersedia pada lingkungan latihan jalur ini, sehingga contoh berikut hanya dibaca dan tidak dieksekusi. Objek Schema menerima satu definisi per field beserta aturannya, sedangkan mongoose.model() menghasilkan model yang terikat pada satu koleksi. Argumen ketiga "pekerjaan" menetapkan nama koleksi secara eksplisit, karena tanpa argumen itu Mongoose menurunkan nama koleksi dari nama model.
// tidak-dijalankan (Mongoose tidak terpasang pada lingkungan latihan jalur ini)
const mongoose = require("mongoose");
const skemaPekerjaan = new mongoose.Schema({
judul: { type: String, required: true, maxlength: 80 },
kategori: { type: String, enum: ["rumah", "pribadi", "belajar"] },
prioritas: { type: Number, min: 1, max: 5, default: 3 },
selesai: { type: Boolean, default: false }
}, { timestamps: true });
const Pekerjaan = mongoose.model("Pekerjaan", skemaPekerjaan, "pekerjaan");
async function main() {
await mongoose.connect("mongodb://127.0.0.1:27017/tugas");
// create() mem-validasi dokumen sebelum mengirimnya ke server
await Pekerjaan.create({ judul: "Belanja mingguan", kategori: "rumah", prioritas: 2 });
const belumSelesai = await Pekerjaan.find({ selesai: false }).sort("prioritas").limit(10);
for (const d of belumSelesai) {
console.log(d.judul, d.prioritas, d.selesai);
}
await mongoose.disconnect();
}
main().catch((e) => { console.error(e); process.exitCode = 1; });Field judul wajib diisi dengan panjang paling banyak 80 karakter, kategori hanya menerima tiga nilai tertentu melalui enum, dan prioritas diberi rentang 1 sampai 5 beserta nilai bawaan 3. Opsi timestamps membuat Mongoose menambahkan field createdAt dan updatedAt secara otomatis pada setiap dokumen. Pemanggilan Pekerjaan.create() memeriksa dokumen terlebih dahulu, sehingga dokumen yang melanggar aturan tidak pernah mencapai server dan errornya dilaporkan di sisi aplikasi.
Tipe yang terdaftar pada schema mencakup String, Number, Boolean, dan Date, sedangkan bentuk ringkas seperti judul: String digunakan ketika tidak ada aturan tambahan. Nilai default diisi ketika field baru tidak disertakan pada dokumen yang dibuat. Model hasilnya juga menyediakan metode query yang setara dengan driver, sehingga filter dan proyeksinya ditulis dalam bentuk yang sama.
Pembanding dengan driver mentah#
Bila validasi dikelola tanpa ODM, aturan yang sama ditulis sebagai fungsi biasa yang dipanggil sebelum setiap penyisipan. Program aplikasi-mentah.js membangun disiplin semacam itu di atas driver mentah. Fungsi validasiPekerjaan memeriksa judul, kategori, dan prioritas, lalu mengembalikan penjelasan kesalahannya atau null. Dokumen yang lolos disisipkan ke koleksi pekerjaan, sedangkan yang ditolak dilaporkan tanpa menyentuh jaringan.
// Validasi skema secara manual di atas driver mentah Node.js
const { MongoClient } = require("mongodb");
const KATEGORI = ["rumah", "pribadi", "belajar"];
function validasiPekerjaan(d) {
if (typeof d.judul !== "string" || d.judul.length === 0 || d.judul.length > 80) {
return "judul wajib string 1-80 karakter";
}
if (!KATEGORI.includes(d.kategori)) {
return "kategori harus salah satu dari " + KATEGORI.join(", ");
}
if (!Number.isInteger(d.prioritas) || d.prioritas < 1 || d.prioritas > 5) {
return "prioritas harus bilangan bulat 1-5";
}
return null;
}
async function main() {
const client = new MongoClient("mongodb://127.0.0.1:27017");
await client.connect();
const koleksi = client.db("tugas").collection("pekerjaan");
// koleksi di-reset agar keluaran program selalu sama
await koleksi.deleteMany({});
const kandidat = [
{ judul: "Belanja mingguan", kategori: "rumah", prioritas: 2 },
{ judul: "Baca artikel basis data", kategori: "belajar", prioritas: 5 },
{ judul: "Rapikan arsip foto", kategori: "hiburan", prioritas: 9 }
];
for (const d of kandidat) {
const masalah = validasiPekerjaan(d);
if (masalah !== null) {
console.log("DITOLAK: " + d.judul + " karena " + masalah);
} else {
await koleksi.insertOne(d);
console.log("DISIMPAN: " + d.judul);
}
}
console.log("Dokumen tersimpan:", await koleksi.countDocuments());
await client.close();
}
main().catch((e) => { console.error(e); process.exitCode = 1; });DISIMPAN: Belanja mingguan
DISIMPAN: Baca artikel basis data
DITOLAK: Rapikan arsip foto karena kategori harus salah satu dari rumah, pribadi, belajar
Dokumen tersimpan: 2Program ini menghasilkan perlindungan yang sama dengan ODM untuk kasus sederhana, tetapi seluruh bebannya ada pada kode aplikasi. Dokumen ketiga ditolak karena kategori di luar daftar yang sah, dan penolakan itu terjadi sebelum perintah dikirim. Setiap titik tulisan baru harus mengingat panggilan validasi, dan aturan yang berubah harus dicari di banyak berkas. Biaya pendekatan ini bukan pada jumlah barisnya, melainkan pada disiplin yang harus dijaga, karena fungsi validasi hanya berjalan pada jalur yang memanggilnya. Perbandingan inilah yang menunjukkan nilai ODM secara tepat, yaitu memusatkan aturan pada satu definisi schema dan menegakkannya di setiap jalur tulisan secara otomatis.
Program dijalankan dari folder topik dengan penyiapan NODE_PATH yang sama dengan contoh Node.js lain pada modul ini.
# menetapkan lokasi package driver, lalu menjalankan program Node.js
export NODE_PATH=/home/kal/tools/node-driver/node_modules
node aplikasi-mentah.jsDISIMPAN: Belanja mingguan
DISIMPAN: Baca artikel basis data
DITOLAK: Rapikan arsip foto karena kategori harus salah satu dari rumah, pribadi, belajar
Dokumen tersimpan: 2Memilih antara driver mentah dan ODM#
Pemilihan ditentukan oleh bentuk aplikasi, bukan oleh ukuran basis datanya. Driver mentah cocok untuk skrip pendek, alat bantu administrasi, dan pipeline agregasi yang bentuknya khusus, karena tanpa lapisan tambahan perilakunya persis seperti dokumentasi server. ODM membantu pada aplikasi yang model datanya stabil dan disentuh banyak modul, karena schema terpusat mencegah perbedaan interpretasi antar bagian kode. Keduanya dapat hidup berdampingan pada satu proyek, dengan ODM untuk jalur CRUD rutin dan driver mentah untuk query khusus. Sisi lain yang perlu dihitung adalah ketergantungan, karena versi ODM mengikuti versi driver dan versi server tertentu, sehingga peningkatan versi perlu diperiksa pada matriks kompatibilitasnya.
| Aspek | Driver mentah | ODM seperti Mongoose |
|---|---|---|
| definisi schema | tersebar di kode aplikasi | terpusat pada model |
| validasi | ditulis sendiri | bawaan per field |
| konversi tipe | manual | otomatis |
| pipeline agregasi | langsung tersedia | lewat metode tambahan |
| ketergantungan | satu package driver | package ODM dan versinya |
Satu batasan penting perlu diingat sebelum memilih ODM. Schema ODM menegakkan aturan di sisi aplikasi saja, sedangkan validator koleksi menegakkannya di sisi server untuk setiap jalur tulisan, termasuk dari mongosh dan dari aplikasi lain. Keduanya saling melengkapi dan bukan pengganti satu sama lain, sehingga aturan yang benar-benar kritis ditegakkan di kedua sisi.
Kesalahan umum#
Kesalahan pertama adalah menganggap schema ODM melindungi server. Validasi Mongoose berjalan di proses aplikasi, sehingga dokumen yang disisipkan dari mongosh atau dari bagian aplikasi yang tidak menggunakan model lolos tanpa diperiksa. Bila aturan wajib dipatuhi semua jalur tulisan, tegakkan aturan tersebut juga dengan validator koleksi di sisi server.
Kesalahan kedua adalah menyunting dokumen yang dibuat ODM langsung lewat driver mentah. Dokumen milik model membawa field internal dan konvensi konversi tipenya, sedangkan tulisan lewat driver tidak mengetahui keduanya. Akibatnya dokumen berada di luar dugaan model, misalnya field updatedAt tidak diperbarui padahal isi dokumen berubah. Pilih satu jalur tulisan untuk satu koleksi dan pertahankan secara konsisten.
Kesalahan ketiga adalah membiarkan query model berjalan tanpa filter dan batas. Metode find() tanpa argumen pada ODM sama mudahnya dengan find({}) pada driver, dan kenyamanannya justru membuat seluruh koleksi termuat ke memori tanpa disadari. Terapkan kebiasaan yang sama seperti pada driver mentah, yaitu membatasi field dengan proyeksi dan jumlah dokumen dengan limit.
Ringkasan#
- ODM membungkus driver resmi dengan definisi schema, konversi tipe otomatis, dan validasi yang berjalan di sisi aplikasi sebelum tulisan dikirim.
- Mongoose menetapkan aturan per field pada objek
Schema, dan model hasilnya terikat pada satu koleksi secara eksplisit. - Validasi manual di atas driver mentah menghasilkan perlindungan yang sama untuk kasus sederhana, tetapi aturannya tersebar dan mudah terlewat.
- Schema ODM menegakkan aturan di sisi aplikasi saja, sedangkan validator koleksi menegakkannya di sisi server untuk semua jalur tulisan.
Referensi#
- Schemas — Mongoose — Definisi schema, tipe field, dan opsi pada Mongoose.
- Validation — Mongoose — Cara Mongoose menegakkan aturan sebelum tulisan dikirim ke server.
- SchemaTypes — Mongoose — Tipe field yang tersedia beserta perilaku konversinya.
- Schema Validation — MongoDB Manual — Validator koleksi yang menegakkan aturan di sisi server.
- MongoDB Node.js Driver — MongoDB Documentation — Driver mentah yang berada di bawah ODM.