Ping di Chapter sebelumnya membuktikan instalasi bekerja — tetapi satu file koneksi yang layak pakai masih punya tiga kebutuhan lain: membaca connection string dari luar kode, menutup koneksi apa pun yang terjadi, dan memberi kita cara mengamati saat koneksi berubah keadaan. Kesalahan paling umum di titik ini adalah membuat MongoClient baru untuk setiap operasi: setiap pembuatan menanggung handshake penuh dan membebani server. Chapter ini merakit file koneksi yang benar untuk aplikasi JavaScript, lalu mengamatinya dari sisi sukses, sisi gagal, dan sisi event.

Connection String dan Handle Database #

Connection string adalah satu-satunya alamat yang dikenal driver: mongodb://host:port/?options. Untuk server latihan kita, bentuknya mongodb://127.0.0.1:27017/?directConnection=true — parameter directConnection membuat driver bicara langsung ke satu server tanpa mencari daftar anggota replica set. Anatomi lengkap string produksi (kredensial, authSource, TLS, mongodb+srv://) sudah kita bahas di Chapter Konfigurasi Koneksi Aman pada Section Keamanan — di sini kita cukup membacanya dari environment variable MONGODB_URI, bukan menuliskannya di dalam kode.

Dua method penting tidak menyentuh jaringan sama sekali:

js Handle database dan collection bersifat lokal
// mdtest: skip — potongan ilustrasi, dijalankan sebagai bagian file lain
const client = new MongoClient(uri)      // hanya mengurai URI dan opsi
const db = client.db("toko_buku")        // handle database — tanpa I/O
const buku = db.collection("buku")       // handle collection — tanpa I/O

client.db() dan db.collection() sekadar menyiapkan object penunjuk; database dan collection sungguhan baru diciptakan server saat operasi tulis pertama. Koneksi jaringan dibuka oleh connect() — atau ditunda sampai operasi pertama bila connect() tidak dipanggil. Kita mengikuti gaya eksplisit karena galat konfigurasi langsung terlihat saat startup, bukan menunggu request pertama.

File Koneksi dengan close() di Blok finally #

Berikut pola dasar yang akan dipakai berulang di seluruh Section ini — perhatikan letak close():

js
// koneksi.js — pola dasar koneksi database dengan driver Node.js
// Jalankan: MONGODB_URI="mongodb://127.0.0.1:27017/?directConnection=true" node koneksi.js
const { MongoClient } = require("mongodb")

const uri = process.env.MONGODB_URI ?? "mongodb://127.0.0.1:27017/?directConnection=true"
const client = new MongoClient(uri, { serverSelectionTimeoutMS: 5000 })

async function main() {
  // Handle database dan collection bisa dibuat kapan saja — murni object lokal.
  const db = client.db("toko_buku")
  const buku = db.collection("buku")
  console.log("1. handle siap, nama collection:", buku.collectionName)

  try {
    await client.connect()
    console.log("2. connect() selesai — koneksi sungguhan baru terbuka di sini")

    const ping = await client.db("admin").command({ ping: 1 })
    console.log("3. ping:", "ok =", ping.ok)
  } finally {
    await client.close()
    console.log("4. koneksi ditutup di blok finally — selalu, apa pun hasilnya")
  }
}

main().catch(err => {
  console.error("GAGAL:", err.name, "-", err.message)
  process.exit(1)
})
bash
MONGODB_URI="mongodb://127.0.0.1:27017/?directConnection=true" node koneksi.js

Output yang Dihasilkan:

text
1. handle siap, nama collection: buku
2. connect() selesai — koneksi sungguhan baru terbuka di sini
3. ping: ok = 1
4. koneksi ditutup di blok finally — selalu, apa pun hasilnya

Mari kita bedah bagian-bagiannya: new MongoClient(uri, { serverSelectionTimeoutMS: 5000 }) menggabungkan URI dengan opsi konstruktor — di sini batas menunggu server dipangkas dari bawaan 30 detik menjadi 5 detik agar kegagalan cepat terlihat. client.db("admin").command({ ping: 1 }) menjalankan command administratif pada database admin; balasan ok = 1 berarti rantai driver-jaringan-server hidup. Penempatan close() di blok finally adalah inti pola ini: connect() boleh sukses lalu operasi berikutnya melempar galat — tanpa finally, koneksi terbuka tertinggal dan proses bisa berhenti tanpa melepasnya.

Ketika Server Tidak Dijangkau #

Bentuk galat koneksi paling sering dijumpai saat server mati atau URI salah. File berikut sengaja diarahkan ke port tanpa server (27099) lewat MONGODB_URI:

js
// gagal-koneksi.js — mengamati bentuk galat ketika server tidak dapat dijangkau
// Jalankan dengan URI yang menunjuk port tanpa server (27099):
// MONGODB_URI="mongodb://127.0.0.1:27099/?directConnection=true&serverSelectionTimeoutMS=3000" node gagal-koneksi.js
const { MongoClient } = require("mongodb")

const uri = process.env.MONGODB_URI ?? "mongodb://127.0.0.1:27017/?directConnection=true"
const client = new MongoClient(uri)

async function main() {
  console.log("mencoba connect() ...")
  try {
    await client.connect()
    console.log("terhubung")
  } catch (err) {
    console.log("tertangkap di catch :", err.name)
    console.log("pesan               :", err.message.split("\n")[0])
    return
  } finally {
    await client.close()
    console.log("finally tetap jalan : client.close() dipanggil")
  }
}

main().catch(err => {
  console.error("GAGAL:", err.name, "-", err.message)
  process.exit(1)
})
bash
MONGODB_URI="mongodb://127.0.0.1:27099/?directConnection=true&serverSelectionTimeoutMS=3000" node gagal-koneksi.js

Output yang Dihasilkan:

text
mencoba connect() ...
tertangkap di catch : MongoServerSelectionError
pesan               : connect ECONNREFUSED 127.0.0.1:27099
finally tetap jalan : client.close() dipanggil

MongoServerSelectionError berarti driver sudah mencoba semua kandidat server dan tidak menemukan satu pun yang sehat dalam batas serverSelectionTimeoutMS (3 detik, dari parameter URI di perintah jalankan). Pesan ECONNREFUSED adalah laporan sistem operasi bahwa tidak ada yang mendengarkan di port tersebut.

Memantau Topologi lewat Event #

Jika galat mengalir lewat exception, perubahan keadaan koneksi justru teramati lewat event. MongoClient memancarkan event monitoring sejak sebelum connect() — kita cukup memasang listener:

js
// pantau-event.js — memantau perubahan topologi lewat event MongoClient
// Jalankan: MONGODB_URI="mongodb://127.0.0.1:27017/?directConnection=true" node pantau-event.js
const { MongoClient } = require("mongodb")

const uri = process.env.MONGODB_URI ?? "mongodb://127.0.0.1:27017/?directConnection=true"
const client = new MongoClient(uri)

// Event topologi: aktif sejak sebelum connect(), dipancarkan saat keadaan berubah
for (const nama of ["serverOpening", "serverDescriptionChanged", "topologyDescriptionChanged", "connectionPoolCreated", "connectionCreated", "open"]) {
  client.on(nama, () => console.log(`[event] ${nama}`))
}

async function main() {
  await client.connect()
  await client.db("admin").command({ ping: 1 })
  console.log("ping ok — sekarang menutup koneksi")
  await client.close()
  console.log("selesai")
}

main().catch(err => {
  console.error("GAGAL:", err.name, "-", err.message)
  process.exit(1)
})
bash
MONGODB_URI="mongodb://127.0.0.1:27017/?directConnection=true" node pantau-event.js

Output yang Dihasilkan:

text
[event] topologyDescriptionChanged
[event] serverOpening
[event] connectionPoolCreated
[event] serverDescriptionChanged
[event] topologyDescriptionChanged
[event] connectionCreated
[event] open
ping ok — sekarang menutup koneksi
selesai

Urutan itu menceritakan proses di balik layar: serverOpening menandai driver mulai memeriksa satu kandidat server, connectionPoolCreated menyiapkan pool koneksi, serverDescriptionChanged mencatat status berubah dari Unknown menjadi Standalone, dan open mengumumkan topologi siap melayani operasi. Pada produksi, event serverDescriptionChanged dan topologyDescriptionChanged adalah bahan mentah logging ketika failover terjadi — kita akan memakainya lagi di Chapter Graceful Shutdown dan bab-bab operasional.

Rangkuman #

  • Baca connection string dari MONGODB_URI; client.db() dan db.collection() hanyalah handle lokal tanpa aktivitas jaringan.
  • Panggil connect() secara eksplisit agar galat muncul di startup, verifikasi dengan client.db("admin").command({ ping: 1 }), dan taruh close() di blok finally.
  • Server yang tidak dijangkau memunculkan MongoServerSelectionError setelah batas serverSelectionTimeoutMS — ditangkap sebagai rejection Promise, bukan event.
  • Event serverOpening, serverDescriptionChanged, dan open memancarkan perubahan keadaan topologi untuk kebutuhan monitoring.