Tutorial MongoDB— Belajar Syntax Dasar di MongoDB

Belajar Dasar MongoDB dengan studi kasus Todo List

Hudya
12 min readMar 14, 2020

Halo semua Kiddy disini, dan pada kesempatan kali ini gue mau berbagi insight mengenai Mongo DB yang berlatar belakang NoSQL. Bisa dibilang gue agak ketinggalan sih berbagi insight mengenai Mongo DB karena ini teknologi database udah lama dipake sebenernya. Gue sendiri pun belom sepenuhnya menggunakan MongoDB, cuma pernah ngulik diawal 2016 saat semester 2 perkuliahan tapi karena masih bego saat itu jadi ngga paham kenapa harus pake NoSQL dibandingkan RDBMS (MySQL)? Akhirnya yaudah cuma asal nyoba dan paham apa gunanya NoSQL tanpa mendalami.

Tapi akhir-akhir ini gue ngerasa udah cukup sucks pake RDBMS dan pengen ngejajal move sepenuhnya ke DOB (Document-oriented Database).

Tapi perlu teman-teman ketahui ya kita tidak boleh mendewakan sebuah teknologi, tentu saja ada kelemahannya dan tidak boleh merasa spesial (Pride, salah satu dosa dari tujuh dosa dalam programming).

Kenapa gue mau pindah ke NoSQL?

Anti Struktur

Saking gampangnya NoSQL dimodify, kita ngga perlu ribet lagi tuh mikirin column apa yang harus ditambahkan kedalam database kita, which is kita ngga perlu ribet-ribet lagi buat migration karena NoSQL bersifat dinamis dan bisa ngikutin apa yang kita butuhkan, but kita harus perhatikan kita juga perlu mikirin untuk mongo perlu di index ngga sih? Yaudah ntar aja kita bahas.

Cocok untuk Horizontal Scaling

src: https://www.intouchdata.com/

Horizontal scaling adalah memecah server menjadi beberapa server ketimbang mengupgrade sebuah server menjadi lebih raksasa, gampangnya ya dijadikan microservice lah~

Dengan menggunakan NoSQL, membuat Horizontal scaling semakin mudah karena emang NoSQL didesain untuk diskala melalui data center yang bersifat multiple. (https://medium.com/swlh/should-you-use-nosql-or-sql-db-or-both-349cb26c9add)

Tanpa Model

Kalo dengan RDBMS kita harus ribet-ribet kita perlu setting model, kita hanya perlu membuat schema saja pada NoSQL. Tentunya kita juga ngga akan ribet sama yang namanya migration hehehe.

Laradock User Guide

Untuk pengguna Laradock, pertama pastiin dulu kalian enable mongo di .env kalian:

WORKSPACE_INSTALL_MONGO=true

Untuk yang menggunakan laradock jangan lupa dibuild dulu ya:

sudo docker-compose up -d mongo

Setelah itu masuk ke workspacenya mongo:

sudo docker-compose exec mongo bash

Silahkan ketik “mongo” lalu enter.

Oke kita dah siap untuk menggunakan MongoDB.

Kicking your ass with the MongoDB

Nah kita akan bermain dengan studi kasus Todo List seperti biasa.

Silahkan buat database baru dengan cara mudah:

use (namadb);

example:

use todolist;

Gampang banget kan? Emangg~

Oke Sekarang kita perlu ngebuat table user kita as usually.

Jadi table di MongoDB diberi nama collections, tapi kita juga bisa show table kok. Caranya adalah

show tables

Pasti kosong karena kita belum buat hahaha. Yuk kita buat table Users dulu dengan cara langsung aja isi collectionnya.

Rumus:

db.(collection).insert({query})//ataudb.(collection).save({query})

Syntax:

db.users.insert({name: "Kiddy", username: "kiddy", password: "123456"})

Sekarang kita tambahkan lagi data baru, karena kita mau coba untuk menggunakan fungsi WHERE seperti di MySQL.

db.users.insert({name: "Hudya", username: "hudya", password: "123456"})

Menampilkan data

Gampang banget cara menampilkan data di MongoDB, literally kalian tinggal tulis seperti syntax dibawah ini:

> db.users.find(){ "_id" : ObjectId("5e6c991a37c2b7308ab4a6ad"), "name" : "Kiddy", "username" : "kiddy", "password" : "123456" }
{ "_id" : ObjectId("5e6c99dc37c2b7308ab4a6ae"), "name" : "Hudya", "username" : "hudya", "password" : "123456" }

Nah muncul semuanya kan? Ini adalah cara untuk menampilkan data tanpa condition, tapi kalo mau pake condition caranya cukup mudah.

db.users.find({condition query})

Contoh:

> db.users.find({ username: "hudya", name: "Hudya" }){ "_id" : ObjectId("5e6c99dc37c2b7308ab4a6ae"), "name" : "Hudya", "username" : "hudya", "password" : "123456" }

Yeay, we found the Hudya data.

Kalo multiple condition gimana? Chill tinggal gini aja.

> db.users.find({ username: "hudya", name: "Hudya" }){ "_id" : ObjectId("5e6c99dc37c2b7308ab4a6ae"), "name" : "Hudya", "username" : "hudya", "password" : "123456" }

Mungkin ada yang bertanya _id dan ObjectId tuh apaan?

_id itu adalah kolom id pada RDBMS, bisa diganti ngga bang? Ya ini udah bawaan template cuy, kalo mau ya nambahin aja kolom “id”, ya tapi ngapain ditambahin kalo udah ada kan? Jangan ribet-ribet wkwkwk.

Sedangkan ObjectId adalah:

An ObjectId is a 12 byte binary BSON type that contain any 12 bytes you want.

Yang kalo diartiin ini sebenernya tipe biner 12 byte dari BSON yang bisa berisi 12 byte apa aja yang kita mau.

Bisa ngga bang kalo saya langsung isi _id-nya?

Bisa banget, nih buktinya:

> db.users.insert({_id: "2", name: "Andi", username: "andi", password: "123456"})
WriteResult({ "nInserted" : 1 })
> db.users.find()
{ "_id" : ObjectId("5e6c991a37c2b7308ab4a6ad"), "name" : "Kiddy", "username" : "kiddy", "password" : "123456" }
{ "_id" : ObjectId("5e6c99dc37c2b7308ab4a6ae"), "name" : "Hudya", "username" : "hudya", "password" : "123456" }
{ "_id" : "2", "name" : "Andi", "username" : "andi", "password" : "123456" }

Bisa ngga bang kalo saya isi pake UUID?

Kita coba aja deh daripada saya dibilang omdo:

> db.users.insert({_id: "3f886a00-ac55-41cd-bd78-4332d64dda85", name: "Budi", username: "budi", password: "123456"})
WriteResult({ "nInserted" : 1 })
> db.users.find()
{ "_id" : ObjectId("5e6c991a37c2b7308ab4a6ad"), "name" : "Kiddy", "username" : "kiddy", "password" : "123456" }
{ "_id" : ObjectId("5e6c99dc37c2b7308ab4a6ae"), "name" : "Hudya", "username" : "hudya", "password" : "123456" }
{ "_id" : "2", "name" : "Andi", "username" : "andi", "password" : "123456" }
{ "_id" : "3f886a00-ac55-41cd-bd78-4332d64dda85", "name" : "Budi", "username" : "budi", "password" : "123456" }

Gimana cara search pake id bang kalo misalnya pake bawaan ObjectId?

> db.users.find({ _id: ObjectId(“5e6c991a37c2b7308ab4a6ad”) })
{ “_id” : ObjectId(“5e6c991a37c2b7308ab4a6ad”), “name” : “Kiddy”, “username” : “kiddy”, “password” : “123456” }

Gampil kan? Tapi saya prefer pake UUID sih kenapa? Gampang karena String hehehe. Kalo di Golang, ribet tuh parsing dari BSONnya (pengalaman, apa emang sayanya aja masih bego ya? xixixi ya maklum ak masih anak piyik 🐣).

Okey udah basa-basinya, sekarang kita lanjut ke table todonya.

Insert ke table todo, disini saya akan menggunakan ID UUID si Budi.

db.todo.insert({ user_id: "3f886a00-ac55-41cd-bd78-4332d64dda85", title: "Coba todo list", description: "Coba aja", created_at: Date(), updated_at: Date() })

Pake stylenya Laravel ya ada created_at sama updated_at ahahaha.

Nah kalo saya coba untuk select datanya akan muncul sebagai berikut.

> db.todo.find(){ “_id” : ObjectId(“5e6c9d34c9396116d82961cc”), “user_id” : “3f886a00-ac55–41cd-bd78–4332d64dda85”, “title” : “Coba todo list”, “description” : “Coba aja”, “created_at” : “Sat Mar 14 2020 09:00:36 GMT+0000 (UTC)”, “updated_at” : “Sat Mar 14 2020 09:00:36 GMT+0000 (UTC)” }

Silahkan masukan satu data lagi.

db.todo.insert({ user_id: "3f886a00-ac55-41cd-bd78-4332d64dda85", title: "Coba todo list lagi", description: "Coba aja lagi", created_at: Date(), updated_at: Date() })

Hasilnya:

> db.todo.find(){ “_id” : ObjectId(“5e6c9d34c9396116d82961cc”), “user_id” : “3f886a00-ac55–41cd-bd78–4332d64dda85”, “title” : “Coba todo list”, “description” : “Coba aja”, “created_at” : “Sat Mar 14 2020 09:00:36 GMT+0000 (UTC)”, “updated_at” : “Sat Mar 14 2020 09:00:36 GMT+0000 (UTC)” }
{ “_id” : ObjectId(“5e6cb49bc9396116d82961cd”), “user_id” : “3f886a00-ac55–41cd-bd78–4332d64dda85”, “title” : “Coba todo list lagi”, “description” : “Coba aja lagi”, “created_at” : “Sat Mar 14 2020 10:40:27 GMT+0000 (UTC)”, “updated_at” : “Sat Mar 14 2020 10:40:27 GMT+0000 (UTC)” }

Nah sekarang kita akan coba mengupdate data, perbedaannya mengupdate data pada table todo.

db.todo.update({ _id: ObjectId(“5e6c9d34c9396116d82961cc”)},{ title: “Sudah bukan coba” })

Apa ekspektasi kalian? Apakah hanya titlenya saja yang berubah?

Realita:

> db.todo.find()
{ “_id” : ObjectId(“5e6c9d34c9396116d82961cc”), “title” : “Sudah bukan coba” }
{ “_id” : ObjectId(“5e6cb49bc9396116d82961cd”), “user_id” : “3f886a00-ac55–41cd-bd78–4332d64dda85”, “title” : “Coba todo list lagi”, “description” : “Coba aja lagi”, “created_at” : “Sat Mar 14 2020 10:40:27 GMT+0000 (UTC)”, “updated_at” : “Sat Mar 14 2020 10:40:27 GMT+0000 (UTC)” }

Terdapat perbedaan antara NoSQL dan MySQL (RDBMS), apabila kita menggunakan fungsi update dan tidak memasukkan semua kolom yang kita ingin rubah maka hasilnya semua akan digantikan dengan data yang kita update saja. Huft, kalo gini berarti NoSQL jelek dong? Ups tunggu dulu, ada caranya gan.

Sekarang kita coba menambahkan aggregate $set kedalam fungsi update. Biar kita ubah bagian titlenya saja.

db.todo.update({ _id: ObjectId(“5e6cb49bc9396116d82961cd”)},{$set: { title: “coba todo list besok lagi” }})

Hasilnya adalah sebagai berikut:

> db.todo.find()
{ “_id” : ObjectId(“5e6c9d34c9396116d82961cc”), “title” : “Sudah bukan coba” }
{ “_id” : ObjectId(“5e6cb49bc9396116d82961cd”), “user_id” : “3f886a00-ac55–41cd-bd78–4332d64dda85”, “title” : “coba todo list besok lagi”, “description” : “Coba aja lagi”, “created_at” : “Sat Mar 14 2020 10:40:27 GMT+0000 (UTC)”, “updated_at” : “Sat Mar 14 2020 10:40:27 GMT+0000 (UTC)” }

Nah hanya titlenya saja yang berubah kan pada value kedua? Itulah fungsi aggregate $set, mengubah yang kita ingin ubah saja columnya tanpa mengubah keseluruhan value.

Nah karena “_id” : ObjectId(“5e6c9d34c9396116d82961cc”) cukup menyampah, kita hapus saja ya.

db.todo.deleteOne({“_id” : ObjectId(“5e6c9d34c9396116d82961cc”)})

Apabila kita coba temukan:

> db.todo.find(){ "_id" : ObjectId("5e6cb49bc9396116d82961cd"), "user_id" : "3f886a00-ac55-41cd-bd78-4332d64dda85", "title" : "coba todo list besok lagi", "description" : "Coba aja lagi", "created_at" : "Sat Mar 14 2020 10:40:27 GMT+0000 (UTC)", "updated_at" : "Sat Mar 14 2020 10:40:27 GMT+0000 (UTC)" }

Oke CRUD udah selesai nih, tapi masih ada yang kurang, sekiranya apa ya?
Kita punya dua table, users dan todo, dan todo memiliki user_id, pertanyaan logisnya adalah, gimana caranya kita melakukan JOIN dari todo ke users ya? Biar kita bisa tau informasi siapa user yang menulis todo list tersebut.

Sempet jadi pertentangan awal NoSQL rilis karena belum ada fitur join, namun sejak MongoDB versi 3.2 kita bisa melakukan fungsi aggregate $lookup yang fungsinya sama seperti Left Join pada RDBMS. Cakep banget kan?

Tapi sebelumnya kita tambahin dulu yuk beberapa data todolist untuk budi, Hudya dan Kiddy.

Disini kita akan menggunakan bulk insert, apaan tuh? Sama aja kaya mass insert atau intinya insert sekaligus banyak. Caranya cukup mudah, didalam query insert kita ganti dengan array terlebih dahulu.

db.todo.insert(
[
{ user_id: "3f886a00-ac55-41cd-bd78-4332d64dda85", title: "Budi Todo List", description: "Todo", created_at: Date(), updated_at: Date() },
{ user_id: "3f886a00-ac55-41cd-bd78-4332d64dda85", title: "Budi Todo List 2", description: "Budi Todo List 2", created_at: Date(), updated_at: Date() },
{ user_id: "3f886a00-ac55-41cd-bd78-4332d64dda85", title: "Budi Todo List 3", description: "Budi Todo List 3", created_at: Date(), updated_at: Date() },
{ user_id: ObjectId(“5e6c991a37c2b7308ab4a6ad”), title: "Kiddy Todo List", description: "Kiddy Todo List", created_at: Date(), updated_at: Date() },
{ user_id: ObjectId(“5e6c991a37c2b7308ab4a6ad”), title: "Kiddy Todo List 2", description: "Kiddy Todo List 2", created_at: Date(), updated_at: Date() },
{ user_id: ObjectId("5e6c99dc37c2b7308ab4a6ae"), title: "Hudya Todo List", description: "Hudya Todo List", created_at: Date(), updated_at: Date() },
]
)

//Hasil
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 6,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})

Nah apabila muncul BulkWriteResult bagian nInsertednya 6, maka berhasil dan kita bisa cek data kita banyak ngga.

> db.todo.find()
{ “_id” : ObjectId(“5e6cb49bc9396116d82961cd”), “user_id” : “3f886a00-ac55–41cd-bd78–4332d64dda85”, “title” : “coba todo list besok lagi”, “description” : “Coba aja lagi”, “created_at” : “Sat Mar 14 2020 10:40:27 GMT+0000 (UTC)”, “updated_at” : “Sat Mar 14 2020 10:40:27 GMT+0000 (UTC)” }
{ “_id” : ObjectId(“5e6cbc1602dd39170405a6db”), “user_id” : “3f886a00-ac55–41cd-bd78–4332d64dda85”, “title” : “Budi Todo List”, “description” : “Todo”, “created_at” : “Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)”, “updated_at” : “Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)” }
{ “_id” : ObjectId(“5e6cbc1602dd39170405a6dc”), “user_id” : “3f886a00-ac55–41cd-bd78–4332d64dda85”, “title” : “Budi Todo List 2”, “description” : “Budi Todo List 2”, “created_at” : “Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)”, “updated_at” : “Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)” }
{ “_id” : ObjectId(“5e6cbc1602dd39170405a6dd”), “user_id” : “3f886a00-ac55–41cd-bd78–4332d64dda85”, “title” : “Budi Todo List 3”, “description” : “Budi Todo List 3”, “created_at” : “Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)”, “updated_at” : “Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)” }
{ “_id” : ObjectId(“5e6cbc1602dd39170405a6de”), “user_id” : ObjectId(“5e6c991a37c2b7308ab4a6ad”), “title” : “Kiddy Todo List”, “description” : “Kiddy Todo List”, “created_at” : “Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)”, “updated_at” : “Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)” }
{ “_id” : ObjectId(“5e6cbc1602dd39170405a6df”), “user_id” : ObjectId(“5e6c991a37c2b7308ab4a6ad”), “title” : “Kiddy Todo List 2”, “description” : “Kiddy Todo List 2”, “created_at” : “Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)”, “updated_at” : “Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)” }
{ “_id” : ObjectId(“5e6cbc1602dd39170405a6e0”), “user_id” : ObjectId(“5e6c99dc37c2b7308ab4a6ae”), “title” : “Hudya Todo List”, “description” : “Hudya Todo List”, “created_at” : “Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)”, “updated_at” : “Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)” }

Wah banyak nih, cakep buat ngetes Lookup alias JOIN. Sekarang kita coba fungsi Lookupnya. Kita akan menggunakan fungsi syntax aggregate, bukan find lagi. Dokumen lengkapnya ada disini.

Sok kita coba.

> db.todo.aggregate([ { $lookup: { from: "users", localField: "user_id", foreignField: "_id", as: "users" }}]);{ "_id" : ObjectId("5e6cb49bc9396116d82961cd"), "user_id" : "3f886a00-ac55-41cd-bd78-4332d64dda85", "title" : "coba todo list besok lagi", "description" : "Coba aja lagi", "created_at" : "Sat Mar 14 2020 10:40:27 GMT+0000 (UTC)", "updated_at" : "Sat Mar 14 2020 10:40:27 GMT+0000 (UTC)", "users" : [ { "_id" : "3f886a00-ac55-41cd-bd78-4332d64dda85", "name" : "Budi", "username" : "budi", "password" : "123456" } ] }
{ "_id" : ObjectId("5e6cbc1602dd39170405a6db"), "user_id" : "3f886a00-ac55-41cd-bd78-4332d64dda85", "title" : "Budi Todo List", "description" : "Todo", "created_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "updated_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "users" : [ { "_id" : "3f886a00-ac55-41cd-bd78-4332d64dda85", "name" : "Budi", "username" : "budi", "password" : "123456" } ] }
{ "_id" : ObjectId("5e6cbc1602dd39170405a6dc"), "user_id" : "3f886a00-ac55-41cd-bd78-4332d64dda85", "title" : "Budi Todo List 2", "description" : "Budi Todo List 2", "created_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "updated_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "users" : [ { "_id" : "3f886a00-ac55-41cd-bd78-4332d64dda85", "name" : "Budi", "username" : "budi", "password" : "123456" } ] }
{ "_id" : ObjectId("5e6cbc1602dd39170405a6dd"), "user_id" : "3f886a00-ac55-41cd-bd78-4332d64dda85", "title" : "Budi Todo List 3", "description" : "Budi Todo List 3", "created_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "updated_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "users" : [ { "_id" : "3f886a00-ac55-41cd-bd78-4332d64dda85", "name" : "Budi", "username" : "budi", "password" : "123456" } ] }
{ "_id" : ObjectId("5e6cbc1602dd39170405a6de"), "user_id" : ObjectId("5e6c991a37c2b7308ab4a6ad"), "title" : "Kiddy Todo List", "description" : "Kiddy Todo List", "created_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "updated_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "users" : [ { "_id" : ObjectId("5e6c991a37c2b7308ab4a6ad"), "name" : "Kiddy", "username" : "kiddy", "password" : "123456" } ] }
{ "_id" : ObjectId("5e6cbc1602dd39170405a6df"), "user_id" : ObjectId("5e6c991a37c2b7308ab4a6ad"), "title" : "Kiddy Todo List 2", "description" : "Kiddy Todo List 2", "created_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "updated_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "users" : [ { "_id" : ObjectId("5e6c991a37c2b7308ab4a6ad"), "name" : "Kiddy", "username" : "kiddy", "password" : "123456" } ] }
{ "_id" : ObjectId("5e6cbc1602dd39170405a6e0"), "user_id" : ObjectId("5e6c99dc37c2b7308ab4a6ae"), "title" : "Hudya Todo List", "description" : "Hudya Todo List", "created_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "updated_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "users" : [ { "_id" : ObjectId("5e6c99dc37c2b7308ab4a6ae"), "name" : "Hudya", "username" : "hudya", "password" : "123456" } ] }

Sekarang kita bisa liat ada array users didalam todo kita. Nah array users ini berisi data dari siapa si pembuat todo tersebut.

Mungkin sekarang agan bertanya lagi, gimana cara supaya nemuin Todo dari sebuah user aja? Oh gampil, kita tinggal tambahkan fungsi $match pada pipeline di aggregate kita.

Misalnya disini saya cuma mau nampiln Todo yang user_idnya si Hudya saja.

> db.todo.aggregate([ { $lookup: { from: "users", localField: "user_id", foreignField: "_id", as: "users" }}, {$match: {"user_id": ObjectId("5e6c99dc37c2b7308ab4a6ae") }} ]){ "_id" : ObjectId("5e6cbc1602dd39170405a6e0"), "user_id" : ObjectId("5e6c99dc37c2b7308ab4a6ae"), "title" : "Hudya Todo List", "description" : "Hudya Todo List", "created_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "updated_at" : "Sat Mar 14 2020 11:12:22 GMT+0000 (UTC)", "users" : [ { "_id" : ObjectId("5e6c99dc37c2b7308ab4a6ae"), "name" : "Hudya", "username" : "hudya", "password" : "123456" } ] }

Mantep kan? Gimana? Gampang ngga NoSQL? Harusnya sih bagi yang sudah terbiasa dengan JSON dan kebiasaan menulis query-query di MySQL akan cepat paham, tinggal gimana kita ngebiasaainnya aja hehehe. Kedepannya saya juga akan mulai bikin Database pake NoSQL, so staytune!

--

--

Hudya
Hudya

Written by Hudya

Which is more difficult, coding or counting? Not both of them, the difficult one is sharing your knowledge to people without asking the payment.

Responses (2)