Driver murni memberi kita kendali penuh, tetapi juga memindahkan semua disiplin ke tangan kita: tidak ada yang melarang satu document memakai field tahun bertipe string sementara document lain memakai angka. Mongoose adalah ODM (Object Data Mapper) untuk MongoDB yang berdiri di atas driver resmi — ia menambahkan lapisan schema, validasi, dan middleware tanpa mengganti cara kerja server. Bab ini menghubungkan Mongoose pertama kali, membedah apa yang diberikannya, dan yang sama pentingnya: kapan lapisan itu justru tidak diperlukan.
Koneksi dan Model Pertama #
Pasang Mongoose seperti biasa (npm install mongoose) — di lingkungan latihan kita paket 9.x sudah tersedia. Satu panggilan mongoose.connect() menggantikan seluruh modul db.js dari bab driver: koneksi disimpan global di mongoose.connection dan otomatis dibagikan ke semua model:
// hello-mongoose.js — koneksi dan model pertama dengan Mongoose
const mongoose = require("mongoose")
const uri =
process.env.MONGODB_URI ??
"mongodb://127.0.0.1:27017/?directConnection=true"
async function main() {
await mongoose.connect(uri, { dbName: "latihan_node_mongoose" })
console.log("1. terhubung, database:", mongoose.connection.name)
// mulai dari keadaan bersih agar contoh dapat diulang
await mongoose.connection.db.dropDatabase()
const bukuSchema = new mongoose.Schema({
judul: { type: String, required: true },
penulis: String,
tahun: Number,
harga: { type: Number, default: 0 },
})
const Buku = mongoose.model("Buku", bukuSchema) // collection "bukus"
const buku = await Buku.create({
judul: "Laskar Pelangi",
penulis: "Andrea Hirata",
tahun: "2005", // sengaja string: Mongoose akan meng-casting
harga: 95000,
})
console.log("2. tersimpan, _id bertipe:", buku._id.constructor.name)
console.log("3. tahun setelah casting:", buku.tahun, "| typeof:", typeof buku.tahun)
const polos = await Buku.findOne({ judul: "Laskar Pelangi" }).lean()
console.log("4. hasil findOne().lean():", JSON.stringify(polos))
console.log("5. collection yang terpakai:", Object.keys(mongoose.connection.collections))
await mongoose.disconnect()
console.log("6. koneksi ditutup")
}
main().catch((err) => {
console.error("GAGAL:", err.name, "-", err.message)
process.exit(1)
})cd /home/z/my-project/tutorial
MONGODB_URI="mongodb://127.0.0.1:27017/?directConnection=true" node content/mongodb/mongodb-dengan-nodejs/menggunakan-mongoose/hello-mongoose.jsOutput yang Dihasilkan:
1. terhubung, database: latihan_node_mongoose
2. tersimpan, _id bertipe: ObjectId
3. tahun setelah casting: 2005 | typeof: number
4. hasil findOne().lean(): {"_id":"6ad3f37a034336ef958c7f27","judul":"Laskar Pelangi","penulis":"Andrea Hirata","tahun":2005,"harga":95000,"__v":0}
5. collection yang terpakai: [ 'bukus' ]
6. koneksi ditutupEmpat peristiwa pada output itu adalah kartu nama Mongoose. mongoose.connect(uri, { dbName }) memilih database lewat opsi, bukan lewat path URI. mongoose.model("Buku", skema) mengubah nama model Buku menjadi collection bukus — pluralisasi otomatis yang bisa diganti dengan argumen nama collection eksplisit. Nilai tahun yang kita kirim sebagai string "2005" keluar sebagai angka 2005 karena SchemaType melakukan casting sebelum menyimpan. Terakhir, __v: 0 adalah versionKey internal untuk optimistik concurrency; .lean() mengembalikan objek JavaScript polos tanpa method document, pilihan yang tepat saat kita hanya ingin membaca.
Kita bedah bagian-bagian kuncinya:
new mongoose.Schema({...})— peta field ke tipe.judulwajib diisi (required: true),penulispolos bertipeString, danhargapunya nilai cadangan0bila tidak dikirim.mongoose.model("Buku", bukuSchema)— mendaftarkan constructor model; dari siniBuku.create(),Buku.find(), dan operasi lain tersedia.Buku.create({...})— membuat sekaligus menyimpan satu document, melewati casting dan validasi schema lebih dulu.mongoose.connection.db.dropDatabase()— bukti bahwa objekDbmilik driver asli tetap terjangkau dari dalam Mongoose.mongoose.disconnect()— menutup koneksi global; padananclient.close()pada driver.
Apa yang Diberikan ODM #
Mongoose menjawab tiga kebutuhan yang sebelumnya harus kita bangun sendiri di atas driver:
| Kebutuhan | Di driver murni | Di Mongoose |
|---|---|---|
| Bentuk document | konvensi tim, tanpa penegakan | Schema mendefinisikan field dan tipe |
| Integritas data | jsonSchema di server, atau tidak sama sekali | validasi required, enum, min/max sebelum operasi |
| Logika lintas-operasi | ditulis manual di setiap fungsi | middleware pre/post per event |
| Relasi antar collection | $lookup manual | ref + populate() |
Skema juga menjadi dokumentasi yang hidup: membaca bukuSchema langsung memberi tahu field apa saja yang diharapkan beserta tipenya, tanpa perlu membuka contoh document di database. Posisi Mongoose dalam arsitektur juga perlu dipahami sejak awal: ia tidak menggantikan driver, melainkan membungkusnya. Setiap operasi Buku.find() pada akhirnya menjadi operasi find pada driver yang sama, melalui connection pool yang sama — sehingga seluruh pemahaman kita tentang connection string, pool, dan timeout dari Section Integrasi Aplikasi tetap berlaku sepenuhnya.
Kapan Tidak Perlu Mongoose #
Lapisan tambahan selalu membawa biaya, dan ada situasi ketika Mongoose justru menghambat. Pertama, pekerjaan ETL dan migrasi data berskala besar: insertMany ratusan ribu document lebih cepat lewat driver karena tidak melewati casting dan pelacakan per document (kita ukur angkanya di bab terakhir section ini). Kedua, skrip administratif sekali jalan yang menyalin atau memeriksa data — tidak ada domain model yang perlu dijaga. Ketiga, aplikasi yang didominasi aggregation pipeline kompleks: pipeline tetap ditulis sama, sementara hasilnya biasanya dibaca dengan .lean() sehingga mayoritas fitur Mongoose tidak terpakai. Keempat, tim yang sudah memiliki lapisan validasi dan repository matang — menambah ODM berarti dua sumber kebenaran untuk bentuk data.
Sisa section ini membedah Mongoose lapis demi lapis: schema dan model (bab berikutnya), validasi, middleware siklus hidup, relasi antar collection lewat populate, aggregation, dan transaksi. Semua contoh memakai koneksi global yang sama, jadi pola connect() di awal dan disconnect() di akhir file akan berulang — itulah praktik yang nanti kita bawa ke aplikasi sungguhan.
Rangkuman #
mongoose.connect()menyimpan satu koneksi global;mongoose.model()mengikat schema ke collection (nama dijamak secara otomatis).- Schema memberi casting tipe (
"2005"menjadi2005), validasi, dan dokumentasi bentuk document;_iddan__vdikelola otomatis. .lean()mengembalikan objek polos untuk pembacaan cepat tanpa fitur document.- Mongoose layak dipakai saat bentuk data dan integritasnya penting; lewati untuk ETL berskala besar, skrip administratif, atau aplikasi yang didominasi aggregation.