Katalog toko buku online kita hidup dari empat aksi dasar: menambah judul baru, mencari buku, memperbarui harga dan stok, serta membuang data yang tidak lagi dijual. Di mongosh kita memakai insertOne dan find; di PyMongo nama method-nya sama persis hanya bergaya Python: insert_one dan find. Yang berbeda adalah cara membaca hasil operasi — setiap method mengembalikan objek result dengan atribut yang informatif, dan tipe data Python diterjemahkan otomatis ke BSON.
Peta materi Chapter ini:
insert_one/insert_manybesertainserted_iddaninserted_ids.- Pemetaan tipe Python ↔ BSON, termasuk
datetimeuntuk field Date. find_one, iterasifind, dan pencarian berdasarkan_id.update_one,update_many,delete_one,delete_manybeserta hitungan hasilnya.
Menulis Data #
Kita kerjakan katalog dari nol. Database latihan dijatuhkan lebih dulu agar skrip ini selalu menghasilkan output yang sama betapa pun sering dijalankan ulang:
import os
from datetime import datetime, timezone
from pymongo import MongoClient
URI = os.environ.get(
"MONGODB_URI", "mongodb://127.0.0.1:27017/?directConnection=true"
)
client = MongoClient(URI, serverSelectionTimeoutMS=5000)
client.drop_database("latihan_crud_py")
db = client["latihan_crud_py"]
# --- CREATE ---
hasil = db.buku.insert_one({
"judul": "Laut Bercerita",
"penulis": "Leila S. Chudori",
"harga": 98000,
"stok": 12,
"tanggal_terbit": datetime.now(timezone.utc),
})
print("insert_one -> acknowledged:", hasil.acknowledged)
print("inserted_id :", hasil.inserted_id)
print("sebagai str :", str(hasil.inserted_id))
hasil_banyak = db.buku.insert_many([
{"judul": "Bumi", "penulis": "Tere Liye",
"harga": 89000, "stok": 25, "tanggal_terbit": datetime.now(timezone.utc)},
{"judul": "Filosofi Teras", "penulis": "Henry Manampiring",
"harga": 89000, "stok": 18, "tanggal_terbit": datetime.now(timezone.utc)},
])
print("insert_many -> jumlah :", len(hasil_banyak.inserted_ids))
# --- READ ---
dok = db.buku.find_one({"penulis": "Tere Liye"})
print("find_one ->", dok["judul"])
print("tersimpan sebagai BSON Date:",
db.buku.count_documents({"tanggal_terbit": {"$type": "date"}}), "document")
print("terbaca di Python sebagai:", type(dok["tanggal_terbit"]).__name__)
dok_id = db.buku.find_one({"_id": hasil.inserted_id})
print("cari by _id ->", dok_id["judul"])
for buku in db.buku.find():
print(f" {buku['judul']} — Rp{buku['harga']} (stok {buku['stok']})")
client.close()Output yang Dihasilkan:
insert_one -> acknowledged: True
inserted_id : 6ad3ef8e9e27b466502cb65f
sebagai str : 6ad3ef8e9e27b466502cb65f
insert_many -> jumlah : 2
find_one -> Bumi
tersimpan sebagai BSON Date: 3 document
terbaca di Python sebagai: datetime
cari by _id -> Laut Bercerita
Laut Bercerita — Rp98000 (stok 12)
Bumi — Rp89000 (stok 25)
Filosofi Teras — Rp89000 (stok 18)Mari kita bedah baris-baris pentingnya:
db.buku.insert_one({...})— document adalahdictPython biasa; hasilnya objekInsertOneResult. Atributinserted_idmemuatObjectIdyang dibuat di sisi klien — di layar ia tampil sebagai string heksadesimal, danstr(...)mengubahnya kestrPython saat kita butuh bentuk itu untuk respons API atau log.datetime.now(timezone.utc)— objekdatetimePython diterjemahkan PyMongo menjadi tipe BSON Date. Query$type: "date"di sisi server membuktikan ketiga document tersimpan dengan tipe itu — tipe yang sama yang tampil sebagaiISODate(...)di mongosh.insert_many([...])— menerimalistofdict;inserted_idsadalah list berisi seluruh_idyang tersimpan, sehinggalen()langsung memberi jumlahnya.
Pemetaan tipe lainnya mengikuti logika yang sama:
| Python | BSON |
|---|---|
dict | document |
list | array |
str | string |
int, float | int32/int64, double |
datetime (aware) | Date |
ObjectId (dari bson.objectid) | ObjectId |
Membaca Data #
find_one mengembalikan satu dict — atau None bila tidak ada yang cocok, jadi selalu periksa hasilnya sebelum mengakses field (dok["judul"] pada None memicu TypeError di Python). Adapun find mengembalikan cursor yang bisa di-loop langsung seperti list; mekanisme lazimya kita bedah tuntas di Chapter Cursor dan Pagination.
Pencarian berdasarkan _id adalah pola yang paling sering dipakai di API: data datang sebagai string dari URL, lalu dikonversi menjadi ObjectId sebelum dikirim sebagai filter. Bentuk konversinya:
from bson.objectid import ObjectId
id_dari_url = "6ad3ef8e9e27b466502cb65f"
dok = db.buku.find_one({"_id": ObjectId(id_dari_url)})Menyaring dengan string mentah ({"_id": id_dari_url}) tidak pernah cocok — BSON ObjectId dan str adalah dua tipe yang berbeda, dan filter MongoDB selalu memperhatikan tipe.
Mengubah dan Menghapus Data #
Operasi tulis berikutnya memakai pola yang sudah dikenal dari mongosh: filter di argumen pertama, perubahan di argumen kedua. File kedua menuntaskan sisa katalog — dan sekalian membersihkan database latihan:
import os
from pymongo import MongoClient
URI = os.environ.get(
"MONGODB_URI", "mongodb://127.0.0.1:27017/?directConnection=true"
)
client = MongoClient(URI, serverSelectionTimeoutMS=5000)
client.drop_database("latihan_crud_py")
db = client["latihan_crud_py"]
db.buku.insert_many([
{"judul": "Laut Bercerita", "penulis": "Leila S. Chudori",
"harga": 98000, "stok": 12},
{"judul": "Bumi", "penulis": "Tere Liye",
"harga": 89000, "stok": 25},
{"judul": "Filosofi Teras", "penulis": "Henry Manampiring",
"harga": 89000, "stok": 18},
{"judul": "Sapiens", "penulis": "Yuval Noah Harari",
"harga": 135000, "stok": 7},
])
# --- UPDATE ---
u1 = db.buku.update_one(
{"judul": "Bumi"},
{"$set": {"harga": 95000}, "$inc": {"stok": 5}},
)
print("update_one -> matched:", u1.matched_count, "| modified:", u1.modified_count)
u2 = db.buku.update_many(
{"harga": {"$gte": 95000}},
{"$set": {"status": "premium"}},
)
print("update_many -> matched:", u2.matched_count, "| modified:", u2.modified_count)
# --- DELETE ---
d1 = db.buku.delete_one({"judul": "Sapiens"})
print("delete_one -> deleted:", d1.deleted_count)
d2 = db.buku.delete_many({"stok": {"$lt": 20}})
print("delete_many -> deleted:", d2.deleted_count)
print("sisa document:", db.buku.count_documents({}))
# bersih-bersih database latihan
client.drop_database("latihan_crud_py")
client.close()Output yang Dihasilkan:
update_one -> matched: 1 | modified: 1
update_many -> matched: 3 | modified: 3
delete_one -> deleted: 1
delete_many -> deleted: 2
sisa document: 1Empat baris output itu merangkum cara membaca hasil operasi:
matched_countvsmodified_count— berapa document yang cocok dengan filter, dan berapa yang benar-benar berubah. Keduanya bisa berbeda: bila nilai baru sama dengan nilai lama, document cocok tetapi tidak dimodifikasi.$setdan$incbisa digabung dalam satu update; operator lain seperti$pushdan$unsetmengikuti sintaks yang sama seperti di mongosh.deleted_count— jumlah document yang dibuang olehdelete_one/delete_many;updatedandeletememakai bentuk filter yang sama persis denganfind.
Rangkuman #
insert_onemengembalikanInsertOneResult(inserted_id,acknowledged);insert_manymengembalikan listinserted_ids.datetimeaware dikonversi ke BSON Date; verifikasi lewat$type: "date";tz_aware=Truemembuat hasil baca membawa timezone.find_onemengembalikandictatauNone;findmengembalikan cursor yang bisa di-loop.- Filter
_idwajib memakaiObjectId(...), bukan string mentah. update_one/update_manymelaporkanmatched_countdanmodified_count; delete melaporkandeleted_count;upsert=Truemenggabungkan update dan insert.
CRUD lengkap sudah berjalan dari Python. Chapter berikutnya memperdalam sisi pembacaan: filter operator, projection, dan pengurutan dalam bentuk dictionary Python.