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
flowchart TD
N0["(" _id: ObjectId('...'"), name: 'Budi', age: 25, ..."]
N1["Table: users id name age 1 Budi 25 2 Ani 30"]
N2["Table: posts iduser_idtitle 1 1 Halo 2 1 Hi"]
N1 --> N2
N2 --> N0
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)
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.
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: