Menu
CoddyTech

Operator Pembaruan

Termasuk bagian Database dengan MongoDB dalam perjalanan Node.js di Coddy. Pelajaran 15 dari 29.

Menambahkan salinan atau tag seharusnya mengubah buku secara langsung, tanpa membacanya, mengubahnya di JavaScript, lalu menulisnya kembali.

$inc menambahkan angka ke sebuah field, dimulai dari 0 jika field tersebut tidak ada. $push menambahkan nilai ke akhir field array, membuat array tersebut jika belum ada. Satu pembaruan dapat memuat beberapa operator:

await players.updateOne(
    { name: 'Ada' },
    { $inc: { wins: 1 }, $push: { badges: 'streak' } }
);

Database menerapkan perubahan itu sendiri, sehingga dua permintaan yang terjadi pada saat yang sama sama-sama dihitung. $set tidak cocok di sini: operator ini mengganti seluruh array badges dengan nilai yang kamu berikan.

challenge icon

Tantangan

Mudah

Rak menghitung jumlah salinan setiap buku yang kamu miliki, dan pembaca dapat menambahkan tag pada buku. Kedua perubahan terjadi di dalam database, masing-masing dengan satu pembaruan, tanpa membaca buku terlebih dahulu.

  1. Di server.js, tambahkan POST /books/:id/copies. Rute ini tidak memerlukan body. Rute ini menambahkan 1 ke field copies pada buku. Buku yang belum memiliki copies akan berakhir dengan "copies": 1.
  2. Tambahkan POST /books/:id/tags. Body menentukan satu tag, misalnya { "tag": "classic" }. Rute ini menambahkan tag ke akhir list tags pada buku dan mempertahankan tag yang sudah ada. Buku yang belum memiliki tags akan berakhir dengan "tags": ["classic"].
  3. Kedua rute menggunakan parseId untuk id yang tidak valid, dan akan menghasilkan 400. Keduanya merespons dengan 404 jika tidak ada buku dengan _id tersebut. Jika tidak, keduanya merespons dengan status 200 dan seluruh buku yang telah diperbarui. Setelah dua salinan dan tag classic lalu favorite, Dune akan terlihat seperti ini:
    { "_id": "6720a1f4c2b9e81d3a5f0c11", "title": "Dune", "author": "Frank Herbert", "year": 1965, "isbn": "9780441013593", "genre": "scifi", "copies": 2, "tags": ["classic", "favorite"] }
    Coba: Kirim GET /books dan salin _id milik Dune. Kirim POST /books/<Dune's _id>/copies dengan body kosong: kamu akan mendapatkan Dune dengan "copies": 1. Kirim sekali lagi: "copies": 2. Kirim POST /books/<Dune's _id>/tags dengan { "tag": "classic" }: "tags": ["classic"]. Kirim sekali lagi dengan { "tag": "favorite" }: "tags": ["classic", "favorite"]. Kirim POST /books/000000000000000000000000/copies: kamu akan mendapatkan 404.

Coba sendiri

import express from 'express';
import { MongoClient, ObjectId } from 'mongodb';

const client = new MongoClient('mongodb://localhost:27017');
const db = client.db('shelf');
const books = db.collection('books');

await books.insertMany([
    { title: 'Dune', author: 'Frank Herbert', year: 1965, isbn: '9780441013593', genre: 'scifi' },
    { title: 'Kindred', author: 'Octavia E. Butler', year: 1979, isbn: '9780807083697', genre: 'scifi' },
    { title: 'Emma', author: 'Jane Austen', year: 1815, isbn: '9780141439587', genre: 'classic' },
]);

const app = express();
app.use(express.json());

// Setiap error menghasilkan respons { error: message }.
function sendError(res, status, message) {
    res.status(status).json({ error: message });
}

// Menghasilkan :id sebagai ObjectId, atau null setelah mengirim respons 400 untuk id yang tidak valid.
function parseId(req, res) {
    if (ObjectId.isValid(req.params.id)) {
        return new ObjectId(req.params.id);
    }
    sendError(res, 400, 'Not a valid id');
    return null;
}

app.get('/', (req, res) => {
    res.send('Bookshelf API');
});

app.get('/books', async (req, res) => {
    const filter = {};
    if (req.query.author) {
        filter.author = req.query.author;
    }
    if (req.query.from || req.query.to) {
        filter.year = {};
        if (req.query.from) {
            filter.year.$gte = Number(req.query.from);
        }
        if (req.query.to) {
            filter.year.$lte = Number(req.query.to);
        }
    }
    const list = await books.find(filter).toArray();
    res.json(list);
});

app.post('/books', async (req, res) => {
    const book = req.body;
    await books.insertOne(book);
    res.status(201).json(book);
});

app.get('/books/newest', async (req, res) => {
    const n = Number(req.query.n) || 3;
    const list = await books
        .find({}, { projection: { title: 1, year: 1, _id: 0 } })
        .sort({ year: -1 })
        .limit(n)
        .toArray();
    res.json(list);
});

app.get('/books/:id', async (req, res) => {
    const id = parseId(req, res);
    if (!id) return;
    const book = await books.findOne({ _id: id });
    if (!book) {
        return sendError(res, 404, 'No such book');
    }
    res.json(book);
});

app.patch('/books/:id', async (req, res) => {
    const id = parseId(req, res);
    if (!id) return;
    const result = await books.updateOne({ _id: id }, { $set: req.body });
    if (result.matchedCount === 0) {
        return sendError(res, 404, 'No such book');
    }
    res.json(await books.findOne({ _id: id }));
});

app.listen(3000, () => {
    console.log('Bookshelf is running on port 3000');
});

Semua pelajaran di Database dengan MongoDB

Latihan sendiri: Playground Express