Menu
CoddyTech

מחיקת מסמכים

חלק מהיחידה מסדי נתונים עם MongoDB במסלול ה-Node.js של Coddy. שיעור 16 מתוך 29.

כדי להסיר ספר צריך קריאה אחת, אבל השרת עדיין צריך להודיע ללקוח אם היה ספר להסיר.

deleteOne(filter) מסירה את המסמך הראשון שתואם למסנן ומחזירה { deletedCount }: 1 אם הוסר מסמך אחד, ו־0 אם לא הייתה התאמה. מחיקה מוצלחת מחזירה 204 No Content, סטטוס שאין לו גוף, ונשלחת באמצעות res.status(204).end().

const result = await sessions.deleteOne({ token });
if (result.deletedCount === 0) {
    // לאף סשן לא היה את ה-token הזה
}

מחיקה של אותו מזהה פעמיים לא אמורה להצליח פעמיים. בפעם השנייה לא נשאר דבר, והלקוח אמור לקבל 404.

challenge icon

אתגר

קל

לקוחות יכולים להסיר ספר, והם צריכים לדעת אם היה ספר להסיר.

  1. ב־server.js, הוסף נתיב DELETE /books/:id. השתמש ב־parseId עבור מזהה שגוי, שמחזיר 400.
  2. כשהנתיב מסיר ספר, השב עם סטטוס 204 וללא גוף כלל. סיים את התגובה בלי לשלוח JSON.
  3. כשאין ספר עם _id כזה, השב עם סטטוס 404 ושגיאה, למשל { "error": "No such book" }. לכן, ניסיון למחוק את אותו הספר בפעם השנייה יחזיר גם הוא 404, כי הספר כבר לא קיים. נסה זאת: שלח GET /books והעתק את _id של Emma. שלח DELETE /books/<Emma's _id>: תקבל 204 וגוף ריק. שלח שוב את אותה בקשה: תקבל 404. שלח GET /books/<Emma's _id>: תקבל גם 404. שלח GET /books: תקבל רק את Dune ואת Kindred, ובכרטיסייה Data יופיעו שני ספרים. לחץ על Run כדי להחזיר את Emma.

נסו בעצמכם

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

// כל שגיאה מחזירה { error: message }.
function sendError(res, status, message) {
    res.status(status).json({ error: message });
}

// החזרת :id בתור ObjectId, או null לאחר החזרת תשובת 400 עבור id לא תקין.
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.post('/books/:id/copies', async (req, res) => {
    const id = parseId(req, res);
    if (!id) return;
    const result = await books.updateOne({ _id: id }, { $inc: { copies: 1 } });
    if (result.matchedCount === 0) {
        return sendError(res, 404, 'No such book');
    }
    res.json(await books.findOne({ _id: id }));
});

app.post('/books/:id/tags', async (req, res) => {
    const id = parseId(req, res);
    if (!id) return;
    const result = await books.updateOne({ _id: id }, { $push: { tags: req.body.tag } });
    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');
});

כל השיעורים ביחידה מסדי נתונים עם MongoDB

תרגלו בעצמכם: Express אונליין