1. NoSQL vs SQL: Perbedaan Mendasar
MongoDB adalah database NoSQL berbasis dokumen yang menyimpan data dalam format BSON (Binary JSON). Berbeda dengan database relasional (SQL) yang menggunakan tabel dan baris, MongoDB menggunakan collections dan documents yang fleksibel dan tidak memerlukan schema tetap.
MongoDB pertama kali dirilis pada tahun 2009 oleh 10gen (sekarang MongoDB Inc.) dan kini menjadi salah satu database paling populer di dunia, digunakan oleh perusahaan seperti Forbes, Toyota, dan banyak startup teknologi. Kemampuannya dalam menangani data semi-terstruktur dan skalabilitas horizontal menjadikannya pilihan utama untuk aplikasi modern.
Perbandingan SQL vs NoSQL
| Aspek | SQL (Relasional) | NoSQL (MongoDB) |
|---|---|---|
| Struktur Data | Tabel dengan baris dan kolom | Documents (JSON/BSON) dalam collections |
| Schema | Ketat β harus didefinisikan di awal | Fleksibel β setiap document bisa berbeda |
| Skalabilitas | Vertikal (upgrade hardware) | Horizontal (tambah server/sharding) |
| Relasi | JOIN antar tabel | Embedding atau referencing manual |
| Bahasa Query | SQL (Structured Query Language) | MongoDB Query Language (MQL) |
| ACID | β Penuh | β Transaksi multi-document (v4.0+) |
| Kasus Penggunaan | Data terstruktur, laporan keuangan | Content management, IoT, real-time analytics |
Kapan Harus Memilih MongoDB?
- Schema berubah-ubah β Saat struktur data sering berubah atau belum ditentukan di awal pengembangan
- Data hierarkis β Data bersarang (nested) seperti komentar dalam postingan blog
- Skalabilitas tinggi β Aplikasi yang perlu menangani jutaan data dengan horizontal scaling
- Development cepat β Prototyping dan MVP yang membutuhkan iterasi cepat
- Real-time analytics β Data yang perlu diproses dan di-query secara real-time
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SQL (Relasional) β
β β
β βββββββββββββββββββ βββββββββββββββββββ β
β β Table: users β β Table: posts β β
β βββββββββββββββββββ€ βββββββββββββββββββ€ β
β β id β name β age β βidβuser_idβtitle β β
β ββββββΌβββββββΌββββββ€ ββββΌββββββββΌβββββββ€ β
β β 1 β Budi β 25 β β1 β 1 β Halo β β
β β 2 β Ani β 30 β β2 β 1 β Hi β β
β βββββββββββββββββββ βββββββββββββββββββ β
β β JOIN β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β NoSQL (MongoDB) β
β β
β Collection: users β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β { β β
β β _id: ObjectId("..."), β β
β β name: "Budi", β β
β β age: 25, β β
β β posts: [ β β
β β { title: "Halo", likes: 10 }, β β
β β { title: "Hi", likes: 5 } β β
β β ] β β
β β } β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2. Instalasi & Setup MongoDB
Ada beberapa cara untuk memulai dengan MongoDB: instalasi lokal, Docker, atau menggunakan layanan cloud MongoDB Atlas yang menyediakan free tier hingga 512 MB storage.
Opsi 1: MongoDB Atlas (Rekomendasi Pemula)
MongoDB Atlas adalah layanan Database-as-a-Service (DBaaS) yang memungkinkan Anda menggunakan MongoDB tanpa instalasi apapun di komputer lokal:
- Buat akun gratis di
mongodb.com/atlas - Buat cluster M0 (gratis, 512 MB)
- Buat database user dan whitelist IP address Anda
- Dapatkan connection string untuk digunakan di aplikasi
Opsi 2: Docker (Untuk Development Lokal)
# Jalankan MongoDB dengan Docker docker run -d \ --name mongodb \ -p 27017:27017 \ -e MONGO_INITDB_ROOT_USERNAME=admin \ -e MONGO_INITDB_ROOT_PASSWORD=password123 \ -v mongodb_data:/data/db \ mongo:7 # Verifikasi container berjalan docker ps | grep mongodb # Masuk ke MongoDB shell docker exec -it mongodb mongosh -u admin -p password123
Opsi 3: Instalasi Lokal
# Ubuntu / Debian wget -qO- https://www.mongodb.org/static/pgp/server-7.0.asc | \ sudo tee /etc/apt/trusted.gpg.d/server-7.0.asc echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu \ jammy/mongodb-org/7.0 multiverse" | \ sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list sudo apt update && sudo apt install -y mongodb-org # macOS dengan Homebrew brew tap mongodb/brew brew install mongodb-community@7.0 # Jalankan service sudo systemctl start mongod # Linux brew services start mongodb-community@7.0 # macOS
Koneksi Pertama dengan mongosh
# Masuk ke MongoDB shell
mongosh
# Atau koneksi ke Atlas
mongosh "mongodb+srv://cluster0.xxxxx.mongodb.net/" --username myUser
# Di dalam shell, cek status
db.runCommand({ ping: 1 })
// Output: { ok: 1 }
# Lihat semua database
show dbs
# Buat / pilih database
use belajar_mongo
# Lihat collection di database saat ini
show collections
3. Documents & Collections
Di MongoDB, data disimpan sebagai documents dalam format BSON (Binary JSON). Setiap document adalah sekumpulan key-value pairs yang dapat berisi berbagai tipe data. Documents dikelompokkan dalam collections β analoginya, collection seperti tabel di SQL, dan document seperti baris (row).
Struktur Document
{
_id: ObjectId("64a7b2c3d4e5f6a7b8c9d0e1"), // Auto-generated, unik
nama: "Budi Santoso",
email: "budi@example.com",
umur: 25,
aktif: true,
alamat: {
jalan: "Jl. Sudirman No. 123",
kota: "Jakarta",
kode_pos: "12190"
},
hobi: ["coding", "membaca", "gaming"],
pendidikan: [
{ institusi: "Universitas Indonesia", tahun: 2022 },
{ institusi: "SMA Negeri 1", tahun: 2018 }
],
created_at: ISODate("2026-06-25T10:30:00Z")
}
Tipe Data yang Didukung
| Tipe | Keterangan | Contoh |
|---|---|---|
| String | Teks UTF-8 | "Hello World" |
| Integer | Bilangan bulat (32/64 bit) | 42, NumberLong(9999999) |
| Double | Bilangan desimal | 3.14 |
| Boolean | True / False | true |
| ObjectId | ID unik 12-byte (default _id) | ObjectId("64a7b2...") |
| Date | Tanggal dan waktu | ISODate("2026-06-25") |
| Array | Kumpulan nilai | ["a", "b", "c"] |
| Object | Dokumen bersarang | { key: "value" } |
| Null | Nilai kosong | null |
| Binary Data | Data biner | BinData(0, "...") |
MongoDB memiliki batas maksimum 16 MB per document. Jika data Anda lebih besar dari itu, pertimbangkan untuk menggunakan GridFS (untuk file) atau memecah data ke beberapa documents dengan referencing.
Embedding vs Referencing
Salah satu keputusan penting dalam desain MongoDB adalah memilih antara embedding (menyimpan data bersama) atau referencing (menyimpan referensi ke document lain):
| Pendekatan | Kelebihan | Kekurangan | Cocok untuk |
|---|---|---|---|
| Embedding | Read cepat, satu query dapat semua data | Document bisa jadi besar, duplikasi data | Data yang sering diakses bersama (1:few) |
| Referencing | Data tidak duplik, document tetap kecil | Perlu multiple queries / $lookup | Data banyak (1:many, many:many) |
4. CRUD Operations
CRUD (Create, Read, Update, Delete) adalah operasi dasar yang harus dikuasai saat bekerja dengan database apapun. Berikut operasi CRUD di MongoDB lengkap dengan berbagai variasinya.
Create β Menyimpan Data
// Insert satu document
db.users.insertOne({
nama: "Budi Santoso",
email: "budi@example.com",
umur: 25,
kota: "Jakarta",
created_at: new Date()
})
// Insert banyak document sekaligus
db.users.insertMany([
{
nama: "Ani Wijaya",
email: "ani@example.com",
umur: 30,
kota: "Bandung",
created_at: new Date()
},
{
nama: "Citra Dewi",
email: "citra@example.com",
umur: 22,
kota: "Surabaya",
created_at: new Date()
},
{
nama: "Dedi Kurniawan",
email: "dedi@example.com",
umur: 28,
kota: "Jakarta",
created_at: new Date()
}
])
// Output:
// {
// acknowledged: true,
// insertedIds: {
// '0': ObjectId("..."),
// '1': ObjectId("..."),
// '2': ObjectId("...")
// }
// }
Read β Membaca Data
// Ambil semua document dalam collection
db.users.find()
// Ambil dengan format yang rapi (pretty print)
db.users.find().pretty()
// Cari berdasarkan field tertentu
db.users.find({ kota: "Jakarta" })
// Cari satu document saja
db.users.findOne({ email: "budi@example.com" })
// Cari berdasarkan ID
db.users.findOne({
_id: ObjectId("64a7b2c3d4e5f6a7b8c9d0e1")
})
// Hitung jumlah document
db.users.countDocuments({ kota: "Jakarta" })
// Output: 2
// Cek apakah document ada
db.users.findOne({ email: "tidakada@example.com" })
// Output: null
Update β Memperbarui Data
// Update satu document β $set mengubah field tertentu
db.users.updateOne(
{ email: "budi@example.com" }, // filter
{ $set: { umur: 26, kota: "Bandung" } } // perubahan
)
// Update β $inc menambah nilai numerik
db.users.updateOne(
{ nama: "Budi Santoso" },
{ $inc: { umur: 1 } } // umur += 1
)
// Update β $push menambah elemen ke array
db.users.updateOne(
{ nama: "Budi Santoso" },
{ $push: { hobi: "berenang" } }
)
// Update β $addToSet menambah tanpa duplikasi
db.users.updateOne(
{ nama: "Budi Santoso" },
{ $addToSet: { hobi: "coding" } } // Tidak ditambah karena sudah ada
)
// Update banyak document sekaligus
db.users.updateMany(
{ kota: "Jakarta" }, // filter
{ $set: { status: "aktif" } } // perubahan
)
// Replace seluruh document (kecuali _id)
db.users.replaceOne(
{ email: "budi@example.com" },
{
nama: "Budi Santoso",
email: "budi@example.com",
umur: 27,
kota: "Yogyakarta",
updated_at: new Date()
}
)
Delete β Menghapus Data
// Hapus satu document
db.users.deleteOne({ email: "dedi@example.com" })
// Hapus banyak document sesuai filter
db.users.deleteMany({ kota: "Jakarta" })
// Hapus SEMUA document dalam collection
db.users.deleteMany({})
// Hapus collection seluruhnya
db.users.drop()
// Hapus database (pilih dulu, lalu drop)
use temp_database
db.dropDatabase()
5. Query & Filtering Lanjutan
MongoDB menyediakan query operators yang sangat kaya untuk filtering data. Operator dimulai dengan tanda $ dan memungkinkan Anda membuat query yang kompleks dan fleksibel.
Comparison Operators
// $eq (equal) β sama dengan
db.users.find({ kota: { $eq: "Jakarta" } })
// Sama dengan: db.users.find({ kota: "Jakarta" })
// $ne (not equal) β tidak sama dengan
db.users.find({ kota: { $ne: "Jakarta" } })
// $gt (greater than) β lebih besar dari
db.users.find({ umur: { $gt: 25 } })
// $gte (greater than or equal) β lebih besar atau sama dengan
db.users.find({ umur: { $gte: 25 } })
// $lt (less than) β kurang dari
db.users.find({ umur: { $lt: 30 } })
// $lte (less than or equal) β kurang atau sama dengan
db.users.find({ umur: { $lte: 25 } })
// $in β nilai ada dalam array
db.users.find({ kota: { $in: ["Jakarta", "Bandung", "Surabaya"] } })
// $nin (not in) β nilai tidak ada dalam array
db.users.find({ kota: { $nin: ["Jakarta", "Bandung"] } })
Logical Operators
// $and β kedua kondisi harus terpenuhi
db.users.find({
$and: [
{ umur: { $gte: 20 } },
{ kota: "Jakarta" }
]
})
// $or β salah satu kondisi terpenuhi
db.users.find({
$or: [
{ umur: { $lt: 23 } },
{ kota: "Bandung" }
]
})
// $not β negasi kondisi
db.users.find({
umur: { $not: { $gte: 30 } }
})
// $nor β tidak ada kondisi yang terpenuhi
db.users.find({
$nor: [
{ kota: "Jakarta" },
{ umur: { $gt: 35 } }
]
})
// Kombinasi kompleks
db.users.find({
$and: [
{ umur: { $gte: 20, $lte: 30 } },
{
$or: [
{ kota: "Jakarta" },
{ kota: "Bandung" }
]
}
]
})
Projection, Sort & Pagination
// Projection β pilih field yang ingin ditampilkan
db.users.find(
{},
{ nama: 1, email: 1, _id: 0 } // 1 = tampilkan, 0 = sembunyikan
)
// Sort β urutkan hasil
db.users.find().sort({ umur: 1 }) // Ascending (AβZ, 0β9)
db.users.find().sort({ umur: -1 }) // Descending (ZβA, 9β0)
// Skip & Limit β pagination
db.users.find()
.sort({ nama: 1 })
.skip(0) // Lewati 0 dokumen (halaman 1)
.limit(10) // Ambil 10 dokumen
// Halaman ke-3 (10 per halaman)
db.users.find()
.sort({ nama: 1 })
.skip(20) // Lewati 20 dokumen
.limit(10)
// Element operators
db.users.find({ hobi: { $exists: true } }) // Field ada
db.users.find({ hobi: { $exists: false } }) // Field tidak ada
db.users.find({ umur: { $type: "int" } }) // Tipe data tertentu
// Regex β pencarian teks
db.users.find({ nama: { $regex: /Budi/i } }) // Case-insensitive
db.users.find({ email: { $regex: /@gmail/ } })
6. Indexes untuk Performa
Index di MongoDB berfungsi sama seperti indeks di buku β mempercepat proses pencarian data. Tanpa index, MongoDB harus melakukan collection scan (memeriksa semua document satu per satu), yang sangat lambat untuk collection besar.
Collection tanpa index yang tepat pada collection dengan jutaan document bisa membutuhkan waktu detik bahkan menit untuk satu query. Dengan index yang tepat, query yang sama bisa selesai dalam milidetik.
Jenis-jenis Index
// Single Field Index β index pada satu field
db.users.createIndex({ email: 1 }) // Ascending
db.users.createIndex({ created_at: -1 }) // Descending
// Unique Index β memastikan nilai unik
db.users.createIndex({ email: 1 }, { unique: true })
// Compound Index β index pada beberapa field
db.users.createIndex({ kota: 1, umur: -1 })
// Text Index β untuk full-text search
db.posts.createIndex({ title: "text", content: "text" })
// Cari dengan text search
db.posts.find({ $text: { $search: "tutorial mongodb" } })
// Partial Index β index hanya untuk dokumen tertentu
db.users.createIndex(
{ email: 1 },
{ partialFilterExpression: { aktif: true } }
)
// TTL Index β auto-delete setelah waktu tertentu
db.sessions.createIndex(
{ created_at: 1 },
{ expireAfterSeconds: 3600 } // Hapus setelah 1 jam
)
Mengelola Index
// Lihat semua index pada collection
db.users.getIndexes()
// Hapus index
db.users.dropIndex({ email: 1 })
db.users.dropIndex("email_1") // Berdasarkan nama
// Hapus semua index kecuali _id
db.users.dropIndexes()
// Explain β analisis performa query
db.users.find({ email: "budi@example.com" }).explain("executionStats")
// Perhatikan: totalDocsExamined β semakin kecil semakin baik
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β B-Tree Index Structure β β β β [M] β β / \ β β [D, H] [P, T] β β / | \ / | \ β β [A,C][F,G][J-L][N-O][R-S][V-X][Z] β β β β Cari "Jakarta": β β Tanpa Index β Scan semua 1,000,000 dokumen (lambat) β β Dengan Index β Traverse B-Tree ~20 langkah (cepat!) β β β β Complexity: O(log n) vs O(n) β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
7. Aggregation Pipeline
Aggregation Pipeline adalah fitur paling powerful di MongoDB untuk memproses dan menganalisis data. Konsepnya mirip dengan GROUP BY di SQL, tetapi jauh lebih fleksibel. Data mengalir melalui serangkaian stages yang memproses dan mentransformasi data secara berurutan.
βββββββββββ βββββββββββ βββββββββββ βββββββββββ βββββββββββ β Input βββββΊβ $match βββββΊβ $group βββββΊβ $sort βββββΊβ Output β βCollectionβ β Filter β β Group & β β Urutkan β β Results β β β β data β β Agregat β β hasil β β β βββββββββββ βββββββββββ βββββββββββ βββββββββββ βββββββββββ 1000 docs 500 docs 20 groups 20 groups 20 results
Contoh Aggregation Pipeline
// Contoh collection "orders":
// { _id, user: "Budi", produk: "Laptop", harga: 12000000, jumlah: 1, status: "selesai" }
// { _id, user: "Ani", produk: "Mouse", harga: 150000, jumlah: 2, status: "selesai" }
// { _id, user: "Budi", produk: "Keyboard",harga: 500000, jumlah: 1, status: "pending" }
// 1. Hitung total pendapatan per user (hanya yang selesai)
db.orders.aggregate([
// Stage 1: Filter hanya order yang selesai
{ $match: { status: "selesai" } },
// Stage 2: Group per user, hitung total
{ $group: {
_id: "$user",
totalPendapatan: { $sum: { $multiply: ["$harga", "$jumlah"] } },
jumlahOrder: { $sum: 1 },
rataRataHarga: { $avg: "$harga" }
}
},
// Stage 3: Urutkan dari pendapatan terbesar
{ $sort: { totalPendapatan: -1 } }
])
// 2. Lookup (JOIN) β gabungkan data dari collection lain
db.orders.aggregate([
{ $lookup: {
from: "users", // Collection yang digabung
localField: "user", // Field di collection ini
foreignField: "nama", // Field di collection lain
as: "userData" // Nama field hasil
}
},
{ $unwind: "$userData" } // "Buka" array menjadi object
])
// 3. Analisis per kota β siapa yang paling banyak belanja?
db.orders.aggregate([
{ $lookup: {
from: "users",
localField: "user",
foreignField: "nama",
as: "userData"
}
},
{ $unwind: "$userData" },
{ $group: {
_id: "$userData.kota",
totalBelanja: { $sum: { $multiply: ["$harga", "$jumlah"] } },
jumlahPembeli: { $addToSet: "$user" }
}
},
{ $project: {
kota: "$_id",
totalBelanja: 1,
jumlahPembeli: { $size: "$jumlahPembeli" }
}
},
{ $sort: { totalBelanja: -1 } }
])
Common Aggregation Stages
| Stage | Fungsi | SQL Equivalent |
|---|---|---|
$match | Filter dokumen | WHERE |
$group | Kelompokkan & agregasi | GROUP BY |
$sort | Urutkan hasil | ORDER BY |
$project | Pilih / bentuk ulang field | SELECT |
$limit | Batasi jumlah hasil | LIMIT |
$skip | Lewati N dokumen | OFFSET |
$lookup | JOIN dengan collection lain | LEFT JOIN |
$unwind | Pecah array jadi dokumen | β |
$addFields | Tambah field baru | Computed column |
$count | Hitung jumlah dokumen | COUNT(*) |
8. Pengenalan Mongoose ODM
Mongoose adalah ODM (Object Data Modeling) library untuk MongoDB dan Node.js. Mongoose menyediakan schema-based solution untuk memodelkan aplikasi Anda, termasuk validasi data, type casting, dan business logic hooks.
Instalasi Mongoose
# Inisialisasi proyek Node.js mkdir mongo-app && cd mongo-app npm init -y # Instal mongoose npm install mongoose # (Opsional) Untuk environment variables npm install dotenv
Mendefinisikan Schema & Model
const mongoose = require('mongoose');
// Definisikan Schema β "blueprint" untuk data
const userSchema = new mongoose.Schema({
nama: {
type: String,
required: [true, 'Nama wajib diisi'],
trim: true,
minlength: [3, 'Nama minimal 3 karakter'],
maxlength: [100, 'Nama maksimal 100 karakter']
},
email: {
type: String,
required: [true, 'Email wajib diisi'],
unique: true,
lowercase: true,
match: [/^\S+@\S+\.\S+$/, 'Format email tidak valid']
},
umur: {
type: Number,
min: [0, 'Umur tidak boleh negatif'],
max: [150, 'Umur tidak valid']
},
role: {
type: String,
enum: ['user', 'admin', 'moderator'],
default: 'user'
},
hobi: {
type: [String],
default: []
},
alamat: {
jalan: String,
kota: String,
kode_pos: String
},
aktif: {
type: Boolean,
default: true
}
}, {
timestamps: true // Auto tambah createdAt & updatedAt
});
// Virtual field β tidak disimpan di database
userSchema.virtual('infoLengkap').get(function() {
return `${this.nama} (${this.email}) - ${this.umur} tahun`;
});
// Middleware (hook) sebelum save
userSchema.pre('save', function(next) {
console.log(`Menyimpan user: ${this.nama}`);
next();
});
// Static method
userSchema.statics.findByKota = function(kota) {
return this.find({ 'alamat.kota': kota });
};
// Instance method
userSchema.methods.isActive = function() {
return this.aktif === true;
};
// Buat Model dari Schema
const User = mongoose.model('User', userSchema);
module.exports = User;
CRUD dengan Mongoose
const mongoose = require('mongoose');
const User = require('./models/User');
// Koneksi ke MongoDB
mongoose.connect('mongodb://localhost:27017/belajar_mongo')
.then(() => console.log('β
Terhubung ke MongoDB'))
.catch(err => console.error('β Error:', err));
async function main() {
// CREATE β buat user baru
const user = new User({
nama: 'Budi Santoso',
email: 'budi@example.com',
umur: 25,
alamat: { jalan: 'Jl. Sudirman 123', kota: 'Jakarta' }
});
await user.save();
console.log('User tersimpan:', user.infoLengkap);
// CREATE β alternatif dengan create()
const users = await User.create([
{ nama: 'Ani', email: 'ani@example.com', umur: 30 },
{ nama: 'Citra', email: 'citra@example.com', umur: 22 }
]);
// READ β cari dengan filter
const jakartaUsers = await User.find({ 'alamat.kota': 'Jakarta' });
const satuUser = await User.findOne({ email: 'budi@example.com' });
// READ β dengan chaining
const hasil = await User
.find({ umur: { $gte: 20 } })
.select('nama email umur')
.sort({ nama: 1 })
.limit(10)
.skip(0);
// UPDATE
await User.updateOne(
{ email: 'budi@example.com' },
{ $set: { umur: 26 } }
);
// Atau gunakan findByIdAndUpdate untuk return document baru
const updated = await User.findByIdAndUpdate(
user._id,
{ $set: { umur: 27 } },
{ new: true } // Return document setelah update
);
// DELETE
await User.deleteOne({ email: 'citra@example.com' });
// Validasi error handling
try {
const invalid = new User({ nama: '', email: 'bad' });
await invalid.save();
} catch (err) {
console.log('Validasi error:', err.errors.nama.message);
// Output: "Nama wajib diisi"
}
}
main();
- Gunakan
lean()untuk query yang lebih cepat saat tidak perlu virtual methods - Manfaatkan
populate()sebagai alternatif dari aggregation$lookup - Selalu tangkap error dari validasi untuk UX yang lebih baik
- Gunakan
select()untuk mengambil hanya field yang dibutuhkan (projection)
9. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang MongoDB: