Tutorial Lengkap MongoDB: Database NoSQL untuk Aplikasi Modern

# Tutorial Lengkap MongoDB: Database NoSQL untuk Aplikasi Modern MongoDB adalah database NoSQL document-oriented yang sangat populer untuk aplikasi modern. Dengan schema yang fleksibel dan kemampuan...

By Ruby Abdullah · · tutorial
MongoDBNoSQLDatabasePythonPyMongoFastAPI

Tutorial Lengkap MongoDB: Database NoSQL untuk Aplikasi Modern

MongoDB adalah database NoSQL document-oriented yang sangat populer untuk aplikasi modern. Dengan schema yang fleksibel dan kemampuan scaling horizontal, MongoDB cocok untuk berbagai use case dari web applications hingga big data analytics.

Apa itu MongoDB?

MongoDB menyimpan data dalam format dokumen JSON-like (BSON) yang memberikan:

  • Schema flexibility: Tidak perlu mendefinisikan struktur data sebelumnya
  • Horizontal scaling: Mudah di-scale dengan sharding
  • High performance: Optimized untuk read/write operations
  • Rich query language: Support complex queries dan aggregations
  • Native replication: Built-in high availability

Use Cases:
  • Content management systems
  • Real-time analytics
  • Mobile applications
  • IoT data storage
  • E-commerce platforms
  • Social media applications

Instalasi MongoDB

1. Install di Ubuntu

# Import MongoDB public GPG key

curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | \

sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor

Add MongoDB repository

echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | \

sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list

Update dan install

sudo apt update

sudo apt install -y mongodb-org

Start MongoDB

sudo systemctl start mongod

sudo systemctl enable mongod

Verify installation

mongosh --eval 'db.runCommand({ connectionStatus: 1 })'

2. Install via Docker

# Pull MongoDB image

docker pull mongo:7.0

Run MongoDB container

docker run -d \

--name mongodb \

-p 27017:27017 \

-e MONGOINITDBROOTUSERNAME=admin \

-e MONGOINITDBROOTPASSWORD=password123 \

-v mongodbdata:/data/db \

mongo:7.0

Connect dengan mongosh

docker exec -it mongodb mongosh -u admin -p password123

3. MongoDB Atlas (Cloud)

Untuk production, MongoDB Atlas menyediakan managed service:

  • Buat akun di MongoDB Atlas
  • Create cluster (free tier tersedia)
  • Configure network access
  • Get connection string
  • # Connection string format
    

    connectionstring = "mongodb+srv://username:password@cluster.mongodb.net/dbname"

    MongoDB Shell (mongosh)

    1. Basic Commands

    // Connect ke MongoDB
    

    mongosh

    // Show databases

    show dbs

    // Use/create database

    use myapp

    // Show collections

    show collections

    // Current database

    db

    // Database stats

    db.stats()

    // Drop database

    db.dropDatabase()

    2. CRUD Operations

    Create (Insert):
    // Insert single document
    

    db.users.insertOne({

    name: "Ruby Abdullah",

    email: "ruby@example.com",

    age: 30,

    skills: ["Python", "JavaScript", "MongoDB"],

    address: {

    city: "Jakarta",

    country: "Indonesia"

    },

    createdAt: new Date()

    })

    // Insert multiple documents

    db.users.insertMany([

    { name: "Alice", email: "alice@example.com", age: 25 },

    { name: "Bob", email: "bob@example.com", age: 35 },

    { name: "Charlie", email: "charlie@example.com", age: 28 }

    ])

    Read (Query):
    // Find all documents
    

    db.users.find()

    // Find dengan filter

    db.users.find({ age: { $gt: 25 } })

    // Find one document

    db.users.findOne({ email: "ruby@example.com" })

    // Projection (select fields)

    db.users.find({}, { name: 1, email: 1, id: 0 })

    // Sort

    db.users.find().sort({ age: -1 }) // Descending

    // Limit dan skip (pagination)

    db.users.find().skip(10).limit(5)

    // Count

    db.users.countDocuments({ age: { $gt: 25 } })

    Update:
    // Update one document
    

    db.users.updateOne(

    { email: "ruby@example.com" },

    { $set: { age: 31 } }

    )

    // Update many documents

    db.users.updateMany(

    { age: { $lt: 30 } },

    { $set: { status: "young" } }

    )

    // Replace entire document

    db.users.replaceOne(

    { email: "bob@example.com" },

    { name: "Bob Smith", email: "bob@example.com", age: 36 }

    )

    // Upsert (update or insert)

    db.users.updateOne(

    { email: "new@example.com" },

    { $set: { name: "New User", age: 20 } },

    { upsert: true }

    )

    Delete:
    // Delete one document
    

    db.users.deleteOne({ email: "alice@example.com" })

    // Delete many documents

    db.users.deleteMany({ age: { $lt: 25 } })

    // Delete all documents in collection

    db.users.deleteMany({})

    3. Query Operators

    Comparison:
    // Equal
    

    db.users.find({ age: 30 })

    // Not equal

    db.users.find({ age: { $ne: 30 } })

    // Greater than / less than

    db.users.find({ age: { $gt: 25, $lt: 40 } })

    // Greater/less than or equal

    db.users.find({ age: { $gte: 25, $lte: 40 } })

    // In array of values

    db.users.find({ age: { $in: [25, 30, 35] } })

    // Not in array

    db.users.find({ age: { $nin: [25, 30] } })

    Logical:
    // AND (implicit)
    

    db.users.find({ age: { $gt: 25 }, status: "active" })

    // AND (explicit)

    db.users.find({

    $and: [

    { age: { $gt: 25 } },

    { status: "active" }

    ]

    })

    // OR

    db.users.find({

    $or: [

    { age: { $lt: 25 } },

    { status: "premium" }

    ]

    })

    // NOT

    db.users.find({

    age: { $not: { $gt: 30 } }

    })

    // NOR (neither)

    db.users.find({

    $nor: [

    { age: { $lt: 25 } },

    { status: "inactive" }

    ]

    })

    Array:
    // Match array element
    

    db.users.find({ skills: "Python" })

    // Match all elements

    db.users.find({ skills: { $all: ["Python", "MongoDB"] } })

    // Array size

    db.users.find({ skills: { $size: 3 } })

    // Element match (untuk array of objects)

    db.orders.find({

    items: {

    $elemMatch: {

    product: "Laptop",

    quantity: { $gt: 1 }

    }

    }

    })

    Element:
    // Field exists
    

    db.users.find({ phone: { $exists: true } })

    // Field type

    db.users.find({ age: { $type: "int" } })

    Text Search:
    // Create text index first
    

    db.articles.createIndex({ title: "text", content: "text" })

    // Text search

    db.articles.find({ $text: { $search: "mongodb tutorial" } })

    // Text search dengan score

    db.articles.find(

    { $text: { $search: "mongodb" } },

    { score: { $meta: "textScore" } }

    ).sort({ score: { $meta: "textScore" } })

    Indexes

    1. Tipe Index

    // Single field index
    

    db.users.createIndex({ email: 1 }) // 1 = ascending, -1 = descending

    // Compound index

    db.users.createIndex({ lastName: 1, firstName: 1 })

    // Unique index

    db.users.createIndex({ email: 1 }, { unique: true })

    // Text index

    db.articles.createIndex({ content: "text" })

    // Geospatial index

    db.places.createIndex({ location: "2dsphere" })

    // TTL index (auto-delete after time)

    db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })

    2. Index Management

    // List indexes
    

    db.users.getIndexes()

    // Drop index

    db.users.dropIndex("email1")

    // Drop all indexes (except id)

    db.users.dropIndexes()

    // Explain query (check index usage)

    db.users.find({ email: "ruby@example.com" }).explain("executionStats")

    Aggregation Framework

    1. Basic Aggregation

    // Count by field
    

    db.users.aggregate([

    { $group: { id: "$status", count: { $sum: 1 } } }

    ])

    // Average

    db.users.aggregate([

    { $group: { id: null, avgAge: { $avg: "$age" } } }

    ])

    // Multiple aggregations

    db.orders.aggregate([

    { $match: { status: "completed" } },

    {

    $group: {

    id: "$customerId",

    totalOrders: { $sum: 1 },

    totalSpent: { $sum: "$total" },

    avgOrderValue: { $avg: "$total" }

    }

    },

    { $sort: { totalSpent: -1 } },

    { $limit: 10 }

    ])

    2. Aggregation Stages

    // $match - Filter documents
    

    { $match: { status: "active" } }

    // $group - Group dan aggregate

    {

    $group: {

    id: "$category",

    total: { $sum: "$price" },

    avg: { $avg: "$price" },

    min: { $min: "$price" },

    max: { $max: "$price" },

    count: { $sum: 1 }

    }

    }

    // $project - Reshape documents

    {

    $project: {

    name: 1,

    fullName: { $concat: ["$firstName", " ", "$lastName"] },

    yearJoined: { $year: "$createdAt" }

    }

    }

    // $sort - Sort results

    { $sort: { total: -1, name: 1 } }

    // $limit dan $skip

    { $skip: 10 }

    { $limit: 5 }

    // $unwind - Deconstruct array

    { $unwind: "$items" }

    // $lookup - Join collections

    {

    $lookup: {

    from: "products",

    localField: "productId",

    foreignField: "id",

    as: "productDetails"

    }

    }

    // $addFields - Add new fields

    {

    $addFields: {

    totalWithTax: { $multiply: ["$total", 1.1] }

    }

    }

    // $facet - Multiple pipelines

    {

    $facet: {

    byCategory: [

    { $group: { id: "$category", count: { $sum: 1 } } }

    ],

    byStatus: [

    { $group: { id: "$status", count: { $sum: 1 } } }

    ],

    totalCount: [

    { $count: "total" }

    ]

    }

    }

    3. Real-world Aggregation Examples

    // E-commerce: Top selling products
    

    db.orders.aggregate([

    { $unwind: "$items" },

    {

    $group: {

    id: "$items.productId",

    totalSold: { $sum: "$items.quantity" },

    revenue: { $sum: { $multiply: ["$items.price", "$items.quantity"] } }

    }

    },

    {

    $lookup: {

    from: "products",

    localField: "id",

    foreignField: "id",

    as: "product"

    }

    },

    { $unwind: "$product" },

    {

    $project: {

    productName: "$product.name",

    totalSold: 1,

    revenue: 1

    }

    },

    { $sort: { revenue: -1 } },

    { $limit: 10 }

    ])

    // User activity report

    db.events.aggregate([

    {

    $match: {

    timestamp: {

    $gte: ISODate("2024-01-01"),

    $lt: ISODate("2024-02-01")

    }

    }

    },

    {

    $group: {

    id: {

    userId: "$userId",

    day: { $dateToString: { format: "%Y-%m-%d", date: "$timestamp" } }

    },

    eventCount: { $sum: 1 },

    uniqueActions: { $addToSet: "$action" }

    }

    },

    {

    $group: {

    id: "$id.userId",

    activeDays: { $sum: 1 },

    totalEvents: { $sum: "$eventCount" },

    avgEventsPerDay: { $avg: "$eventCount" }

    }

    },

    { $sort: { totalEvents: -1 } }

    ])

    Python dengan PyMongo

    1. Setup dan Connection

    from pymongo import MongoClient
    

    from pymongo.errors import ConnectionFailure

    from bson.objectid import ObjectId

    from datetime import datetime

    Basic connection

    client = MongoClient("mongodb://localhost:27017/")

    Connection dengan authentication

    client = MongoClient(

    "mongodb://admin:password123@localhost:27017/",

    authSource="admin"

    )

    MongoDB Atlas connection

    client = MongoClient(

    "mongodb+srv://user:password@cluster.mongodb.net/?retryWrites=true&w=majority"

    )

    Test connection

    try:

    client.admin.command('ping')

    print("Connected successfully!")

    except ConnectionFailure:

    print("Connection failed!")

    Select database dan collection

    db = client["myapp"]

    users = db["users"]

    2. CRUD dengan PyMongo

    from pymongo import MongoClient
    

    from bson.objectid import ObjectId

    from datetime import datetime

    client = MongoClient("mongodb://localhost:27017/")

    db = client["myapp"]

    users = db["users"]

    Insert

    def createuser(name, email, age):

    user = {

    "name": name,

    "email": email,

    "age": age,

    "createdat": datetime.utcnow()

    }

    result = users.insertone(user)

    return result.insertedid

    Insert many

    def createusers(userlist):

    result = users.insertmany(userlist)

    return result.insertedids

    Read

    def getuserbyemail(email):

    return users.findone({"email": email})

    def getusers(filters=None, limit=10, skip=0):

    query = filters or {}

    return list(users.find(query).skip(skip).limit(limit))

    def getuserbyid(userid):

    return users.findone({"id": ObjectId(userid)})

    Update

    def updateuser(userid, updates):

    result = users.updateone(

    {"id": ObjectId(userid)},

    {"$set": updates}

    )

    return result.modifiedcount

    def incrementage(userid):

    result = users.updateone(

    {"id": ObjectId(userid)},

    {"$inc": {"age": 1}}

    )

    return result.modifiedcount

    Delete

    def deleteuser(userid):

    result = users.deleteone({"id": ObjectId(userid)})

    return result.deletedcount

    Usage

    userid = createuser("Ruby", "ruby@example.com", 30)

    print(f"Created user: {userid}")

    user = getuserbyemail("ruby@example.com")

    print(f"Found user: {user}")

    updateuser(userid, {"age": 31, "status": "active"})

    3. Aggregation dengan PyMongo

    from pymongo import MongoClient
    
    

    client = MongoClient("mongodb://localhost:27017/")

    db = client["ecommerce"]

    orders = db["orders"]

    Aggregation pipeline

    def getsalesbycategory():

    pipeline = [

    {"$unwind": "$items"},

    {

    "$group": {

    "id": "$items.category",

    "totalsales": {"$sum": {"$multiply": ["$items.price", "$items.quantity"]}},

    "totalitems": {"$sum": "$items.quantity"},

    "ordercount": {"$sum": 1}

    }

    },

    {"$sort": {"totalsales": -1}}

    ]

    return list(orders.aggregate(pipeline))

    Customer analytics

    def gettopcustomers(limit=10):

    pipeline = [

    {"$match": {"status": "completed"}},

    {

    "$group": {

    "id": "$customerid",

    "totalspent": {"$sum": "$total"},

    "ordercount": {"$sum": 1},

    "avgordervalue": {"$avg": "$total"}

    }

    },

    {"$sort": {"totalspent": -1}},

    {"$limit": limit},

    {

    "$lookup": {

    "from": "customers",

    "localField": "id",

    "foreignField": "id",

    "as": "customerinfo"

    }

    },

    {"$unwind": "$customerinfo"},

    {

    "$project": {

    "customername": "$customerinfo.name",

    "email": "$customerinfo.email",

    "totalspent": 1,

    "ordercount": 1,

    "avgordervalue": {"$round": ["$avgordervalue", 2]}

    }

    }

    ]

    return list(orders.aggregate(pipeline))

    Time series analysis

    def getdailyrevenue(startdate, enddate):

    pipeline = [

    {

    "$match": {

    "createdat": {"$gte": startdate, "$lt": enddate},

    "status": "completed"

    }

    },

    {

    "$group": {

    "id": {

    "$dateToString": {"format": "%Y-%m-%d", "date": "$createdat"}

    },

    "revenue": {"$sum": "$total"},

    "orders": {"$sum": 1}

    }

    },

    {"$sort": {"id": 1}}

    ]

    return list(orders.aggregate(pipeline))

    4. Index Management

    from pymongo import MongoClient, ASCENDING, DESCENDING, TEXT
    
    

    client = MongoClient("mongodb://localhost:27017/")

    db = client["myapp"]

    users = db["users"]

    Create indexes

    users.createindex("email", unique=True)

    users.createindex([("lastname", ASCENDING), ("firstname", ASCENDING)])

    users.createindex([("location", "2dsphere")])

    users.createindex([("bio", TEXT), ("interests", TEXT)])

    Create TTL index

    sessions = db["sessions"]

    sessions.createindex("createdat", expireAfterSeconds=3600)

    List indexes

    for index in users.listindexes():

    print(index)

    Drop index

    users.dropindex("email1")

    Motor: Async MongoDB Driver

    import asyncio
    

    from motor.motorasyncio import AsyncIOMotorClient

    async def main():

    # Connect

    client = AsyncIOMotorClient("mongodb://localhost:27017/")

    db = client["myapp"]

    users = db["users"]

    # Insert

    result = await users.insertone({

    "name": "Async User",

    "email": "async@example.com"

    })

    print(f"Inserted: {result.insertedid}")

    # Find

    user = await users.findone({"email": "async@example.com"})

    print(f"Found: {user}")

    # Find many

    cursor = users.find({"status": "active"})

    async for doc in cursor:

    print(doc)

    # Aggregation

    pipeline = [

    {"$group": {"id": "$status", "count": {"$sum": 1}}}

    ]

    cursor = users.aggregate(pipeline)

    async for doc in cursor:

    print(doc)

    asyncio.run(main())

    FastAPI dengan MongoDB

    from fastapi import FastAPI, HTTPException
    

    from pydantic import BaseModel, Field

    from typing import Optional, List

    from motor.motorasyncio import AsyncIOMotorClient

    from bson import ObjectId

    from datetime import datetime

    app = FastAPI()

    MongoDB connection

    client = AsyncIOMotorClient("mongodb://localhost:27017/")

    db = client["myapp"]

    Pydantic models

    class PyObjectId(ObjectId):

    @classmethod

    def _getvalidators_(cls):

    yield cls.validate

    @classmethod

    def validate(cls, v, handler):

    if not ObjectId.isvalid(v):

    raise ValueError("Invalid ObjectId")

    return ObjectId(v)

    class UserCreate(BaseModel):

    name: str

    email: str

    age: int

    class UserResponse(BaseModel):

    id: str = Field(alias="id")

    name: str

    email: str

    age: int

    createdat: datetime

    class Config:

    populatebyname = True

    jsonencoders = {ObjectId: str}

    Routes

    @app.post("/users", responsemodel=UserResponse)

    async def createuser(user: UserCreate):

    userdict = user.modeldump()

    userdict["createdat"] = datetime.utcnow()

    result = await db.users.insertone(userdict)

    created = await db.users.findone({"id": result.insertedid})

    created["id"] = str(created["id"])

    return created

    @app.get("/users", responsemodel=List[UserResponse])

    async def getusers(skip: int = 0, limit: int = 10):

    cursor = db.users.find().skip(skip).limit(limit)

    users = await cursor.tolist(length=limit)

    for user in users:

    user["id"] = str(user["id"])

    return users

    @app.get("/users/{userid}", responsemodel=UserResponse)

    async def getuser(userid: str):

    user = await db.users.findone({"id": ObjectId(userid)})

    if not user:

    raise HTTPException(statuscode=404, detail="User not found")

    user["id"] = str(user["id"])

    return user

    @app.put("/users/{userid}", responsemodel=UserResponse)

    async def updateuser(userid: str, user: UserCreate):

    result = await db.users.updateone(

    {"id": ObjectId(userid)},

    {"$set": user.modeldump()}

    )

    if result.modifiedcount == 0:

    raise HTTPException(statuscode=404, detail="User not found")

    updated = await db.users.findone({"id": ObjectId(userid)})

    updated["id"] = str(updated["id"])

    return updated

    @app.delete("/users/{userid}")

    async def deleteuser(userid: str):

    result = await db.users.deleteone({"id": ObjectId(userid)})

    if result.deletedcount == 0:

    raise HTTPException(statuscode=404, detail="User not found")

    return {"message": "User deleted"}

    Run: uvicorn main:app --reload

    Best Practices

    1. Schema Design

    # Embedding vs Referencing
    
    

    Embedding (untuk data yang selalu diakses bersama)

    userwithaddress = {

    "name": "Ruby",

    "email": "ruby@example.com",

    "addresses": [

    {"type": "home", "city": "Jakarta", "country": "Indonesia"},

    {"type": "work", "city": "Bandung", "country": "Indonesia"}

    ]

    }

    Referencing (untuk data yang besar atau sering di-update)

    user = {

    "name": "Ruby",

    "email": "ruby@example.com"

    }

    order = {

    "userid": ObjectId("..."), # Reference ke user

    "items": [...],

    "total": 100

    }

    2. Connection Management

    from pymongo import MongoClient
    

    from contextlib import contextmanager

    Connection pooling

    client = MongoClient(

    "mongodb://localhost:27017/",

    maxPoolSize=50,

    minPoolSize=10,

    maxIdleTimeMS=30000

    )

    Context manager untuk transactions

    @contextmanager

    def getsession():

    with client.startsession() as session:

    yield session

    Usage dengan transaction

    with getsession() as session:

    with session.starttransaction():

    db.users.insertone({"name": "Test"}, session=session)

    db.logs.insertone({"action": "usercreated"}, session=session)

    3. Error Handling

    from pymongo.errors import (
    

    ConnectionFailure,

    DuplicateKeyError,

    WriteError

    )

    def safeinsert(collection, document):

    try:

    result = collection.insertone(document)

    return result.insertedid

    except DuplicateKeyError:

    print("Document already exists")

    return None

    except WriteError as e:

    print(f"Write error: {e}")

    return None

    except ConnectionFailure:

    print("Connection failed")

    return None

    4. Performance Tips

    # Use projection untuk mengurangi data transfer
    

    users.find({}, {"name": 1, "email": 1})

    Batch operations

    from pymongo import InsertOne, UpdateOne

    operations = [

    InsertOne({"name": "User 1"}),

    InsertOne({"name": "User 2"}),

    UpdateOne({"name": "User 1"}, {"$set": {"status": "active"}})

    ]

    result = users.bulkwrite(operations)

    Create appropriate indexes

    users.createindex([("email", 1)], unique=True)

    users.createindex([("status", 1), ("created_at", -1)])

    Kesimpulan

    MongoDB adalah database NoSQL yang powerful dan fleksibel untuk aplikasi modern. Key takeaways:

  • Document-oriented: Data disimpan sebagai dokumen JSON-like
  • Schema flexibility: Tidak perlu schema tetap
  • Rich queries: Support complex queries dan aggregations
  • Scalable: Horizontal scaling dengan sharding
  • Python integration: PyMongo dan Motor untuk sync/async
  • Tips penggunaan:

    • Design schema berdasarkan access patterns
    • Gunakan indexes untuk query yang sering digunakan
    • Leverage aggregation framework untuk analytics
    • Implement proper connection pooling
    • Handle errors gracefully

    Artikel Terkait

    Tutorial LitServe: Framework Serving Model AI yang Cepat dan Mudah

    Tutorial LitServe: Framework Serving Model AI yang Cepat dan Mudah Pendahuluan LitServe adalah framework open-source dar...

    Tutorial Reflex: Membangun Web App Full-Stack dengan Python Murni

    Reflex: Membangun Aplikasi Web Full-Stack dengan Python Murni Reflex memungkinkan Anda membangun aplikasi web lengkap — ...

    SQLModel: ORM Modern Python untuk Aplikasi AI yang Type-Safe

    SQLModel: ORM Modern Python untuk Aplikasi AI yang Type-Safe Dalam pengembangan aplikasi AI/ML, pengelolaan data di data...

    Tutorial Lengkap FastAPI untuk Machine Learning: Building Production ML APIs

    Tutorial Lengkap FastAPI untuk ML: Build Production ML APIs FastAPI adalah framework web Python modern dengan performa t...