MERN Stack
Mongoose

Mongoose

Mongoose adalah sebuah Object Document Mapper (ODM) dan framework JavaScript yang umumnya digunakan pada aplikasi Node.js. Ini berarti Mongoose mengizinkan Anda untuk mendefinisikan obyek dengan skema yang benar-benar diketik yang dipetakan ke sebuah dokumen MongoDB.

Mongoose menyediakan jumlah fungsionalitas yang luar biasa yang berkaitan dengan pembuatan dan pengerjaan skema.

Referensi: An Introduction to Mongoose for MongoDB and Node.js (opens in a new tab)

Instalasi

Install library mongoose dengan menjalankan perintah npm i mongoose.

Install Mongoose

npm i mongoose

Menggunakan Mongoose

Menyambungkan string url mongodb yang sudah kita konfigurasi, kita bisa meletakkan urlnya di sana.

src/index.ts
import mongoose from "mongoose";
 
mongoose.connect(URL);
# contoh
mongoose.connect("mongodb+srv://rezarinaldi:asdfghjkl123456@devscaleid.ubxzvbk.mongodb.net/?retryWrites=true&w=majority&appName=DevscaleID")

Kita bisa juga mengaturnya agar lebih rapi dan aman dengan cara menaruh linknya di file .env.

MONGO_URI="mongoose.connect("mongodb+srv://rezarinaldi:asdfghjkl123456@devscaleid.ubxzvbk.mongodb.net/?retryWrites=true&w=majority&appName=DevscaleID")"

Agar bisa menggunakan url pada .env, kita perlu meng-install library dontenv. Jalankan perintah sebagai berikut.

npm install dotenv

Lalu, panggil library dotenv pada file src/index.ts seperti berikut,

src/index.ts
import dotenv from "dotenv";
 
dotenv.config();

Kemudian, untuk menyambungkan url mongodb yang sudah diletakkan pada file .env ketikan pada file src/index.ts seperti berikut,

src/index.ts
import mongoose from "mongoose";
 
mongoose
  .connect(process.env.MONGO_URI as string)
  .then(() => console.log("connected to mongodb"))
  .catch((err) => console.log(err));

Schema

Define Schema

Contoh dari define schema.

models/userSchema.ts
import { Schema } from "mongoose";
 
const userSchema = new Schema({
  name: String,
  email: String,
  age: Number,
});

Create Model

Selanjutnya, kita coba untuk membuat model dari schema.

models/noteSchema.ts
import { Schema, model } from "mongoose";
 
const noteSchema = new Schema({
  content: String,
  isDone: Boolean,
});
 
export const Note = model("Note", noteSchema);

Relationship

Membuat relationship pada database mongodb. Relationship ada 2 cara, yaitu References dan Embedding.

References

Dalam pendekatan ini, satu dokumen/skema merujuk ke dokumen lain menggunakan ObjectId dokumen target. Hal ini mirip dengan kunci asing dalam basis data relasional.

models/noteSchema.ts
import { Schema, model } from "mongoose";
 
const noteSchema = new Schema({
  content: String,
  isDone: Boolean,
  authorId: { type: Schema.Types.ObjectId, ref: "User" },
});
 
export const Note = model("Note", noteSchema);

Embedding

Penyematan melibatkan penyisipan data terkait dalam satu dokumen/skema. Hal ini berguna ketika kamu memiliki hubungan one-to-one atau one-to-few dan data terkait tidak sering diperbarui.

models/noteSchema.ts
import { Schema, model } from "mongoose";
 
const replySchema = new Schema({
  text: String,
  authorId: { type: Schema.Types.ObjectId, ref: "User" },
});
 
const noteSchema = new Schema({
  content: String,
  isDone: Boolean,
  replies: [replySchema],
});
 
export const Note = model("Note", noteSchema, replySchema);

Kemudian, kita perlu konfigurasi untuk menentukan dari interface dari schema tersebut, agar kita bisa mengatur data dari schema.

Buat folder types kemudian buat file entity.ts. Kemudian, ketikan pada file entity.ts sebagai berikut.

types/entity.ts
export interface INote {
  content: string;
  isDone: boolean;
  authorId: Types.ObjectId;
}

Lalu, coba kita import/panggil entity dari INote pada file models/noteSchema.ts kita tadi.

models/noteSchema.ts
import { Schema, model } from "mongoose";
import { INote } from "../types/entity";
 
const noteSchema = new Schema<INote>({
  content: String,
  isDone: Boolean,
  authorId: { type: Schema.Types.ObjectId, ref: "User" },
});
 
export const Note = model("Note", noteSchema);

CRUD (Create, Read, Update, and Delete)

Kita perlu membuat folder controllers dan membuat file note.controller.ts. Lalu, ketikan seperti di bawah ini.

Create/Insert Data

controllers/note.controller.ts
import { Request, Response } from "express";
import { Note } from "../models/noteSchema";
 
export async function handleCreateNote(req: Request, res: Response) {
  return res.json({ message: "Hello, this from server for Create!" });
}

Read Data

controllers/note.controller.ts
import { Request, Response } from "express";
import { Note } from "../models/noteSchema";
 
export async function handleGetNotes(req: Request, res: Response) {
  return res.json({ message: "Hello, this from server for Read!" });
}

Update/Edit Data

controllers/note.controller.ts
import { Request, Response } from "express";
import { Note } from "../models/noteSchema";
 
export async function handleEditNote(req: Request, res: Response) {
  return res.json({ message: "Hello, this from server for Update!" });
}

Delete Data

controllers/note.controller.ts
import { Request, Response } from "express";
import { Note } from "../models/noteSchema";
 
export async function handleDeleteNote(req: Request, res: Response) {
  return res.json({ message: "Hello, this from server for Delete!" });
}

Router

Kita perlu mengonfigurasi dari router untuk CRUD yang sudah kita buat sebelumnya.

Buat folder routers dan buat file note.router.ts. Kemudian, ketikan seperti berikut.

routers/note.router.ts
import express from "express";
import {
  handleGetNotes,
  handleCreateNote,
  handleEditNote,
  handleDeleteNote,
} from "../controllers/note.controller";
 
export const noteRouter = express();
 
noteRouter.get("/notes", handleGetNotes);
noteRouter.post("/notes", handleCreateNote);
noteRouter.patch("/notes:id", handleEditNote);
noteRouter.delete("/notes:id", handleDeleteNote);

Jangan lupa kita gunakan dan panggil noteRouter kita pada file src/index.ts. Ketikan sebagai berikut.

src/index.ts
import express from "express";
import { noteRouter } from "./routers/note.router";
 
const app = express();
 
app.use("/api", noteRouter);

Kita perlu meng-install library lagi, yaitu cors, agar dapat diakses di sisi client. Jalankan perintah berikut.

npm i cors
npm i -D @types/cors

Kemudian, panggil/import library cors yang sudah di-install pada file src/index.ts.

src/index.ts
import cors from "cors";
 
app.use(cors());

Lalu, kita coba jalankan app kita dengan mengetikan perintah berikut,

npm run dev

Kemudian, buka http://localhost:8000/api/notes pada browser kita. Jika tampil pesan dari server, maka berhasil.


Kita coba melanjutkan untuk CRUD tadi. Ketikan seperti di bawah ini.

Create/Insert Data

controllers/note.controller.ts
import { Request, Response } from "express";
import { Note } from "../models/noteSchema";
 
export async function handleCreateNote(req: Request, res: Response) {
  const { content, isDone, authorId } = req.body;
 
  const newNote = new Note({
    content,
    isDone,
    authorId,
  });
 
  const saveNote = await newNote.save();
 
  return res
    .status(201)
    .json({ message: "A note is just created!", data: saveNote });
}

Read Data

controllers/note.controller.ts
import { Request, Response } from "express";
import { Note } from "../models/noteSchema";
 
export async function handleGetAllNotes(req: Request, res: Response) {
  const allNotes = await Note.find().populate("authorId");
  return res
    .status(201)
    .json({ message: "This is all notes!", data: allNotes });
}

Update/Edit Data

controllers/note.controller.ts
import { Request, Response } from "express";
import { Note } from "../models/noteSchema";
 
export async function handleEditNote(req: Request, res: Response) {
  const { content, isDone, authorId } = req.body;
 
  const noteId = req.params.id;
 
  const updateNote = await Note.findOneAndUpdate(
    { _id: noteId },
    { content, isDone, authorId },
    { new: true }
  );
 
  return res
    .status(201)
    .json({ message: "A note is just updated!", data: updateNote });
}

Delete Data

controllers/note.controller.ts
import { Request, Response } from "express";
import { Note } from "../models/noteSchema";
 
export async function handleDeleteNote(req: Request, res: Response) {
  const noteId = req.params.id;
 
  await Note.findByIdAndDelete(noteId);
  return res.status(201).json("A note is just deleted!");
}

Find

Method find digunakan untuk mencari semua dokumen yang cocok dengan kriteria pencarian tertentu.

Contoh

import { Schema, model } from "mongoose";
 
const userSchema = new Schema({
  nama: String,
  umur: Number,
  email: String,
});
 
const User = model("User", userSchema);
 
// Mencari semua pengguna dengan umur lebih dari 25 tahun
User.find({ umur: { $gt: 25 } }, (err, users) => {
  if (err) {
    console.log(err);
  } else {
    console.log(users);
  }
});

Dalam contoh di atas, find akan mencari semua dokumen di koleksi User di mana nilai umur lebih besar dari 25. Hasil pencarian akan dikembalikan sebagai array dari objek pengguna yang cocok.

FindOne

Method findOne digunakan untuk mencari satu dokumen yang cocok dengan kriteria pencarian tertentu.

Contoh:

import { Schema, model } from "mongoose";
 
const userSchema = new Schema({
  nama: String,
  umur: Number,
  email: String,
});
 
const User = model("User", userSchema);
 
// Mencari satu pengguna dengan nama "Budi"
User.findOne({ nama: "Budi" }, (err, user) => {
  if (err) {
    console.log(err);
  } else {
    console.log(user);
  }
});

Dalam contoh di atas, findOne akan mencari satu dokumen di koleksi User di mana nilai nama adalah "Budi". Hasil pencarian akan dikembalikan sebagai objek pengguna yang pertama kali ditemukan yang cocok dengan kriteria tersebut.

Filtering

Berikut adalah beberapa contoh query penyaringan (filtering) menggunakan Mongoose.

Menyiapkan Skema dan Model

Pertama-tama, mari kita buat skema dan model yang akan kita gunakan untuk contoh-contoh ini.

import { Schema, model } from "mongoose";
 
const userSchema = new Schema({
  nama: String,
  umur: Number,
  email: String,
  aktif: Boolean,
});
 
const User = model("User", userSchema);

Contoh Query Filtering (find)

Method find digunakan untuk mencari semua dokumen yang cocok dengan kriteria pencarian tertentu.

Filtering Berdasarkan Satu Kriteria

Contoh 1: Mencari semua pengguna yang berumur lebih dari 30 tahun.

User.find({ umur: { $gt: 30 } }, (err, users) => {
  if (err) {
    console.log(err);
  } else {
    console.log(users);
  }
});

Dalam contoh di atas, kita menggunakan operator $gt untuk filtering pengguna yang berumur lebih dari 30 tahun.

Filtering Berdasarkan Beberapa Kriteria

Contoh 2: Mencari semua pengguna yang berumur lebih dari 20 tahun dan sedang aktif.

User.find({ umur: { $gt: 20 }, aktif: true }, (err, users) => {
  if (err) {
    console.log(err);
  } else {
    console.log(users);
  }
});

Dalam contoh ini, kita filtering pengguna yang berumur lebih dari 20 tahun dan memiliki status aktif yang bernilai true.

Filtering Menggunakan Operator Logika

Contoh 3: Mencari semua pengguna yang berumur kurang dari 25 tahun atau memiliki nama "Alice".

User.find(
  {
    $or: [{ umur: { $lt: 25 } }, { nama: "Alice" }],
  },
  (err, users) => {
    if (err) {
      console.log(err);
    } else {
      console.log(users);
    }
  }
);

Di sini kita menggunakan operator $or untuk filtering pengguna yang berumur kurang dari 25 tahun atau memiliki nama "Alice".

Filtering Berdasarkan Nilai dalam Daftar Contoh 4: Mencari semua pengguna yang namanya ada dalam daftar tertentu.

User.find({ nama: { $in: ["Budi", "Charlie", "Dewi"] } }, (err, users) => {
  if (err) {
    console.log(err);
  } else {
    console.log(users);
  }
});

Dalam contoh ini, kita menggunakan operator $in untuk filtering pengguna yang namanya ada dalam daftar ["Budi", "Charlie", "Dewi"].

Filtering Menggunakan Pola Regex

Contoh 5: Mencari semua pengguna yang emailnya mengandung domain "example.com".

User.find({ email: /@example\.com$/ }, (err, users) => {
  if (err) {
    console.log(err);
  } else {
    console.log(users);
  }
});

Di sini kita menggunakan regex untuk filtering pengguna yang emailnya berakhir dengan "@example.com".

Contoh Query Filtering (findOne)

Method findOne digunakan untuk mencari satu dokumen yang cocok dengan kriteria pencarian tertentu.

import { Schema, model } from "mongoose";
 
const userSchema = new Schema({
  nama: String,
  umur: Number,
  email: String,
});
 
const User = model("User", userSchema);
 
// Mencari satu pengguna dengan email tertentu
User.findOne({ email: "budi@example.com" }, (err, user) => {
  if (err) {
    console.log(err);
  } else {
    console.log(user);
  }
});

Dalam contoh di atas, findOne akan mencari satu dokumen di koleksi User di mana nilai email adalah "budi@example.com". Hasil pencarian akan dikembalikan sebagai objek pengguna pertama yang ditemukan yang cocok dengan kriteria tersebut.

Contoh Query Filtering (findById)

Method findById digunakan untuk mencari satu dokumen berdasarkan ID-nya.

import { Schema, model } from "mongoose";
 
const userSchema = new Schema({
  nama: String,
  umur: Number,
  email: String,
});
 
const User = model("User", userSchema);
 
// Mencari pengguna berdasarkan ID
const userId = "60c72b2f9b1d4c3d88f1a2e1";
User.findById(userId, (err, user) => {
  if (err) {
    console.log(err);
  } else {
    console.log(user);
  }
});

Dalam contoh di atas, findById akan mencari satu dokumen di koleksi User berdasarkan nilai _id yang diberikan (userId). Hasil pencarian akan dikembalikan sebagai objek pengguna yang ditemukan dengan ID tersebut.

Kesimpulan

  • find digunakan untuk mencari semua dokumen yang cocok dengan kriteria pencarian tertentu dan mengembalikan array dari hasil pencarian.
  • findOne digunakan untuk mencari satu dokumen yang cocok dengan kriteria pencarian tertentu dan mengembalikan objek dokumen pertama yang ditemukan.
  • findById digunakan untuk mencari satu dokumen berdasarkan ID-nya dan mengembalikan objek dokumen yang ditemukan.