mongosh mengeksekusi setiap perintah secara manual, satu kali untuk setiap pengetikan. Aplikasi nyata menjalankan operasi yang sama ribuan kali sehari dari dalam kode melalui driver. Driver adalah pustaka yang menerjemahkan fungsi bahasa pemrograman menjadi perintah MongoDB lalu mengirimkannya ke server. Topik ini membahas driver resmi Node.js, mulai dari pemasangan package, pembuatan koneksi, siklus CRUD lengkap pada koleksi pekerjaan di basis data tugas, sampai padanan setiap operasi mongosh pada kode. Setelah mengikuti topik ini, aplikasi Node.js dapat membaca dan menulis MongoDB tanpa campur tangan shell.
Instalasi driver dan connection string#
Driver resmi Node.js dipublikasikan sebagai package mongodb. Pada proyek sungguhan, package dipasang dari npm dengan npm install mongodb setelah npm init menyiapkan berkas package.json. Lingkungan latihan jalur ini sudah menyediakan package tersebut pada folder tersendiri, sehingga pemasangan ulang tidak diperlukan, dan program cukup diarahkan ke folder itu melalui variabel NODE_PATH pada saat dijalankan. Pola ini dipakai oleh seluruh contoh Node.js pada modul ini.
Koneksi dibangun oleh kelas MongoClient dari package mongodb. Konstruktor menerima connection string, yaitu alamat server berformat mongodb://host:port, misalnya mongodb://127.0.0.1:27017 untuk server lokal tanpa autentikasi. Satu objek klien memelihara kumpulan koneksi ke server dan sebaiknya dibuat satu kali untuk seluruh proses aplikasi. Metode connect() menghubungi server secara asinkron, sedangkan client.db() dan db.collection() hanya menunjuk nama basis data dan koleksi tanpa mengirim apa pun ke jaringan. Koleksi yang belum ada boleh ditunjuk, karena MongoDB menyediakannya pada saat dokumen pertama disisipkan. Connection string juga dapat membawa opsi tambahan sebagai parameter query, misalnya batas waktu pemilihan server atau nama replica set, yaitu kelompok server MongoDB yang menyimpan salinan data yang sama. Opsi semacam itu berlaku untuk seluruh operasi klien, sehingga pengaturan seperti serverSelectionTimeoutMS cukup ditetapkan sekali pada alamatnya.
Menjalankan CRUD dari aplikasi#
Program aplikasi.js menjalankan satu siklus CRUD lengkap pada koleksi pekerjaan, yaitu daftar pekerjaan pribadi dengan field judul, kategori, prioritas, dan selesai. Koleksi di-reset terlebih dahulu agar keluaran program selalu sama, lalu dokumen disisipkan, dibaca, diperbarui, dan dihapus di dalam satu fungsi main asinkron. Setiap metode driver mengembalikan Promise, sehingga setiap operasi harus menunggu dengan await sebelum hasilnya dipakai.
// CRUD pekerjaan pribadi dari aplikasi Node.js
const { MongoClient } = require("mongodb");
const client = new MongoClient("mongodb://127.0.0.1:27017");
async function main() {
await client.connect();
const koleksi = client.db("tugas").collection("pekerjaan");
// koleksi di-reset agar keluaran program selalu sama
await koleksi.deleteMany({});
// CREATE: menyisipkan banyak dokumen sekaligus
const seed = await koleksi.insertMany([
{ judul: "Belanja mingguan", kategori: "rumah", prioritas: 2, selesai: false },
{ judul: "Kirim dokumen pajak", kategori: "pribadi", prioritas: 1, selesai: false },
{ judul: "Ganti filter air", kategori: "rumah", prioritas: 3, selesai: false },
{ judul: "Baca artikel basis data", kategori: "belajar", prioritas: 5, selesai: true }
]);
console.log("Dokumen baru:", seed.insertedCount);
// CREATE: menyisipkan satu dokumen tambahan
await koleksi.insertOne({ judul: "Rapikan arsip foto", kategori: "pribadi", prioritas: 4, selesai: false });
// READ: membaca satu dokumen pertama yang cocok dengan filter
const pajak = await koleksi.findOne({ kategori: "pribadi" }, { sort: { prioritas: 1 } });
console.log("Pertama pribadi:", pajak.judul);
// READ: membaca seluruh dokumen dengan proyeksi
const semua = await koleksi.find({}, { projection: { _id: 0, judul: 1, selesai: 1 } }).sort({ prioritas: 1 }).toArray();
for (const d of semua) {
console.log("[" + (d.selesai ? "x" : " ") + "] " + d.judul);
}
// UPDATE: menandai satu pekerjaan selesai
const ubah = await koleksi.updateOne({ judul: "Belanja mingguan" }, { $set: { selesai: true } });
console.log("Dokumen diubah:", ubah.modifiedCount);
// DELETE: menghapus satu pekerjaan yang tidak dibutuhkan lagi
const hapus = await koleksi.deleteOne({ judul: "Ganti filter air" });
console.log("Dokumen dihapus:", hapus.deletedCount);
console.log("Sisa dokumen:", await koleksi.countDocuments());
await client.close();
}
main().catch((e) => { console.error(e); process.exitCode = 1; });Dokumen baru: 4
Pertama pribadi: Kirim dokumen pajak
[ ] Kirim dokumen pajak
[ ] Belanja mingguan
[ ] Ganti filter air
[ ] Rapikan arsip foto
[x] Baca artikel basis data
Dokumen diubah: 1
Dokumen dihapus: 1
Sisa dokumen: 4Lima baris daftar pada keluaran berasal dari operasi READ. Metode findOne dengan opsi sort mengembalikan pekerjaan pribadi berprioritas tertinggi, sedangkan find dengan proyeksi menyembunyikan field _id yang nilainya dihasilkan server. Baris Dokumen diubah dan Dokumen dihapus mencatat hasil updateOne dan deleteOne berupa jumlah dokumen yang tersentuh. Angka modifiedCount dan deletedCount memberi kepastian bahwa operasi menyasar dokumen yang dimaksud, sesuatu yang tidak dilaporkan mongosh secara eksplisit.
Program dijalankan dari folder topik. Variabel NODE_PATH ditetapkan terlebih dahulu agar package mongodb pada folder latihan dapat ditemukan, kemudian berkasnya dieksekusi dengan node.
# menetapkan lokasi package driver, lalu menjalankan program Node.js
export NODE_PATH=/home/kal/tools/node-driver/node_modules
node aplikasi.jsDokumen baru: 4
Pertama pribadi: Kirim dokumen pajak
[ ] Kirim dokumen pajak
[ ] Belanja mingguan
[ ] Ganti filter air
[ ] Rapikan arsip foto
[x] Baca artikel basis data
Dokumen diubah: 1
Dokumen dihapus: 1
Sisa dokumen: 4Keluaran eksekusi bash berisi baris yang sama dengan blok sebelumnya karena programnya sama dan datanya selalu ditanam ulang dari awal. Program aman dijalankan berulang kali, sehingga keluaran ini dapat dipakai sebagai acuan saat mencoba variasi kode.
Memeriksa hasil dari mongosh#
Data yang ditulis aplikasi adalah data biasa di sisi server, sehingga dapat diperiksa dari mongosh kapan saja. Pemeriksaan semacam ini mempercepat pencarian penyebab masalah, karena kesalahan kode dan kesalahan data dapat dipisahkan dalam satu langkah. Blok berikut menyusun ulang kondisi akhir koleksi pekerjaan yang ditinggalkan program, yaitu pekerjaan yang telah ditandai selesai dan Ganti filter air yang telah dihapus, kemudian membaca pekerjaan yang belum selesai. Hasil insertMany ditampung pada variabel hasil, tetapi hanya jumlah dokumen yang dicetak agar keluarannya tetap ringkas. Tampilan array berindentasi dengan tanda kutip tunggal adalah cara shell merender hasil kursor, dan cara itu tidak mengubah isi datanya.
use tugas
const hasil = db.pekerjaan.insertMany([
{ judul: "Kirim dokumen pajak", kategori: "pribadi", prioritas: 1, selesai: false },
{ judul: "Belanja mingguan", kategori: "rumah", prioritas: 2, selesai: true },
{ judul: "Rapikan arsip foto", kategori: "pribadi", prioritas: 4, selesai: false },
{ judul: "Baca artikel basis data", kategori: "belajar", prioritas: 5, selesai: true }
])
print("Dokumen tersimpan: " + db.pekerjaan.countDocuments())
db.pekerjaan.find({ selesai: false }, { _id: 0, judul: 1, prioritas: 1 }).sort({ prioritas: 1 })switched to db tugas
Dokumen tersimpan: 4
[
{ judul: 'Kirim dokumen pajak', prioritas: 1 },
{ judul: 'Rapikan arsip foto', prioritas: 4 }
]Keluaran menampilkan dua dokumen dengan proyeksi terbatas pada judul dan prioritas, sedangkan field _id disembunyikan karena tidak berarti bagi pembacaan manual. Angka pada Dokumen tersimpan berasal dari countDocuments, sehingga jumlahnya dibaca ulang dari server dan bukan dihitung dari tampilan. Apabila program aplikasi dijalankan lebih dahulu pada lingkungan yang sama, perintah db.pekerjaan.find() menampilkan isi yang sama tanpa perlu menanam data ulang. Kebiasaan memverifikasi hasil tulisan dari shell melengkapi siklus pengembangan, yaitu kode menulis dan shell memeriksa.
Padanan operasi mongosh pada driver#
Setiap metode driver memanggil perintah server yang sama dengan perintah mongosh, sehingga pemetaan antar keduanya berlangsung hampir satu banding satu. Perbedaan yang perlu diadaptasi ada pada bentuk, bukan pada makna. Eksekusi yang di shell berlangsung seketika per baris menjadi asinkron di kode. Proyeksi yang di shell menjadi argumen kedua langsung berpindah ke dalam objek opsi. Hasil tulisan yang di shell dicetak sebagai ringkasan menjadi objek hasil dengan angka tersendiri. Tabel berikut merangkum perbedaan yang paling sering ditemui.
| Aspek | mongosh | Driver Node.js |
|---|---|---|
| sifat eksekusi | langsung per baris | asinkron, menunggu await |
proyeksi pada find | argumen kedua langsung | bagian projection dari objek opsi |
urutan pada findOne | argumen sort pada metode | bagian sort dari objek opsi |
| hasil tulisan | ringkasan cetak | objek hasil dengan insertedCount, modifiedCount, deletedCount |
| hasil pembacaan | kursor yang dicetak otomatis | kursor yang diiterasi atau toArray() |
Filter dan operator update tidak masuk tabel karena tidak berubah sama sekali. Dokumen { $set: { selesai: true } } yang diketik di mongosh dipakai apa adanya sebagai argumen updateOne pada driver, dan begitu pula seluruh operator query lain. Nama metodenya juga mengikuti pola yang sama, yaitu insertMany, findOne, updateOne, dan deleteOne merujuk langsung pada perintah servernya. Konsistensi ini membuat pengetahuan shell menjadi modal langsung untuk kode, dan sebaliknya, operasi yang diragukan dari kode dapat diuji ulang di mongosh dengan perintah yang setara.
Kesalahan umum#
Kesalahan pertama adalah memanggil metode driver tanpa await. Metode tersebut mengembalikan Promise, sehingga kode yang langsung membaca hasilnya menerima objek Promise, bukan dokumen. Kesalahan ini tidak menghentikan program dengan error apa pun. Gejalanya baru terlihat saat field yang dibaca bernilai undefined, atau berupa TypeError pada baris yang mencoba membaca field dari objek Promise tersebut. Perbaikannya adalah menunggu setiap operasi database dengan await di dalam fungsi async.
Kesalahan kedua adalah mencocokkan _id dengan tipe yang salah. Filter { _id: "101" } tidak pernah cocok dengan dokumen yang _id-nya bertipe angka, karena pencocokan MongoDB mempertimbangkan tipe BSON di samping nilainya. Kondisi sebaliknya berlaku sama, yaitu string heksadesimal ObjectId tidak cocok dengan _id bertipe ObjectId sebelum dikonversi dengan kelas ObjectId dari package.
Kesalahan ketiga adalah membuat MongoClient baru untuk setiap operasi. Setiap klien memelihara kumpulan koneksi sendiri, sehingga pembuatan klien berulang menumpuk koneksi dan menambah waktu jabat tangan jaringan. Klien sebaiknya dibuat satu kali pada saat aplikasi dimulai, dipakai bersama oleh seluruh modul, dan ditutup dengan client.close() hanya ketika proses benar-benar berakhir.
Ringkasan#
- Driver Node.js mengakses MongoDB melalui satu objek
MongoClientyang dibuat dari connection string dan dipakai bersama oleh seluruh proses aplikasi. - Metode
insertMany,findOne,find,updateOne, dandeleteOnemenjalankan perintah server yang sama dengan mongosh, dengan filter dan operator yang tidak berubah. - Setiap metode mengembalikan
Promise, sehingga operasi harus menunggu denganawaitdan hasil tulisannya dibaca dariinsertedCount,modifiedCount, ataudeletedCount. - Proyeksi dan urutan menyatu ke dalam objek opsi, sedangkan hasil kursor diiterasi dengan
for awaitatau dimuat dengantoArray().
Referensi#
- Connect to MongoDB — MongoDB Node.js Driver
— Pembuatan
MongoClient, connection string, dan opsi koneksi pada driver Node.js. - Get Started — MongoDB Node.js Driver — Langkah pertama menggunakan driver Node.js, dari pemasangan sampai query pertama.
- CRUD Operations — MongoDB Node.js Driver — Panduan operasi create, read, update, dan delete dari kode Node.js.
- Connection String URI Format — MongoDB Manual — Format alamat server beserta opsinya, termasuk host dan port.
- db.collection.insertOne() — MongoDB Manual — Perintah server yang dipanggil driver saat menyisipkan satu dokumen.