Menu
CoddyTech

Cập nhật tài liệu

Thuộc phần Cơ sở dữ liệu với MongoDB trong hành trình Node.js của Coddy. Bài học 14 trên 29.

Việc sửa năm xuất bản của một cuốn sách chỉ nên thay đổi trường đó và giữ nguyên các trường khác.

updateOne(filter, update) thay đổi tài liệu đầu tiên khớp với bộ lọc. Bản cập nhật gồm các toán tử: $set ghi các trường bạn cung cấp và giữ nguyên mọi trường khác. Một đối tượng thông thường không có toán tử sẽ bị từ chối với thông báo "Update document requires atomic operators".

const result = await players.updateOne(
    { name: 'Ada' },
    { $set: { score: 120, level: 4 } }
);
result.matchedCount;  // 1 nếu tìm thấy người chơi khớp, 0 nếu không
result.modifiedCount; // 0 nếu các giá trị đã giống nhau

Dùng matchedCount, không phải modifiedCount, để phân biệt tài liệu không tồn tại với tài liệu không có gì thay đổi. Bản cập nhật không trả về tài liệu, nên hãy đọc lại bằng findOne.

challenge icon

Thử thách

Dễ

Khách hàng muốn sửa một trường của sách, chẳng hạn như năm xuất bản bị sai, mà không gửi lại toàn bộ thông tin sách.

  1. Trong server.js, bên dưới chú thích // Add PATCH /books/:id here., thêm một tuyến PATCH /books/:id.
  2. Bắt đầu giống như cách GET /books/:id hiện đang bắt đầu: gọi parseId(req, res). Nếu id không hợp lệ, parseId đã phản hồi với mã 400 và trả về null, vì vậy hãy dừng tại đó.
  3. Chỉ thay đổi những trường mà phần thân yêu cầu, còn mọi trường khác giữ nguyên. Phần thân { "year": 1966 } sẽ đổi năm và không thay đổi gì khác.
  4. Nếu không có sách nào mang _id đó, hãy phản hồi với mã trạng thái 404 và một lỗi, ví dụ { "error": "No such book" }.
  5. Nếu không, hãy phản hồi với mã trạng thái 200 và toàn bộ thông tin sách như hiện được lưu:
    { "_id": "6720a1f4c2b9e81d3a5f0c11", "title": "Dune", "author": "Frank Herbert", "year": 1966, "isbn": "9780441013593", "genre": "scifi" }
    Thử ngay: Gửi GET /books và sao chép _id của Dune. Sao chép lại sau mỗi lần bấm Chạy, vì mỗi lần chạy sẽ tạo id mới. Gửi PATCH /books/ kèm theo _id của Dune, với phần thân { "year": 1966 }. Bạn nhận được mã 200 và thông tin Dune với "year": 1966, mọi trường khác đều giữ nguyên, và tab Data cũng hiển thị như vậy. Gửi lại cùng yêu cầu: bạn vẫn nhận được mã 200, vì sách vẫn tồn tại dù lần này không có gì thay đổi. Gửi PATCH /books/000000000000000000000000 với { "year": 1966 }: bạn nhận được mã 404. Gửi PATCH /books/42: bạn nhận được mã 400.

Tự làm thử

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());

// Mọi lỗi đều trả về { error: message }.
function sendError(res, status, message) {
    res.status(status).json({ error: message });
}

// Trả về :id dưới dạng ObjectId, hoặc null sau khi trả về 400 nếu id không hợp lệ.
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);
});

// Thêm PATCH /books/:id vào đây.

app.listen(3000, () => {
    console.log('Bookshelf is running on port 3000');
});
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Cơ sở dữ liệu với MongoDB

Tự luyện tập: Playground Express