Menu
CoddyTech

Dokumente löschen

Teil des Abschnitts Datenbanken mit MongoDB der Node.js-Journey von Coddy. Lektion 16 von 29.

Zum Entfernen eines Buchs genügt ein Aufruf, aber der Server muss dem Client trotzdem mitteilen, ob ein Buch zum Entfernen vorhanden war.

deleteOne(filter) entfernt das erste passende Dokument und liefert { deletedCount }: 1, wenn ein Dokument entfernt wurde, 0, wenn nichts passte. Bei erfolgreichem Löschen lautet die Antwort 204 No Content, ein Status ohne Antworttext, gesendet mit res.status(204).end().

const result = await sessions.deleteOne({ token });
if (result.deletedCount === 0) {
    // Keine Sitzung hatte diesen Token
}

Dieselbe ID zweimal zu löschen, sollte nicht zweimal erfolgreich sein. Beim zweiten Mal ist nichts mehr vorhanden, und der Client sollte den Status 404 erhalten.

challenge icon

Aufgabe

Einfach

Clients können ein Buch entfernen und müssen wissen, ob es ein Buch zum Entfernen gab.

  1. Füge in server.js eine Route DELETE /books/:id hinzu. Verwende bei einer ungültigen ID parseId; dabei wird der Statuscode 400 zurückgegeben.
  2. Wenn die Route ein Buch entfernt, antworte mit dem Statuscode 204 und ohne jeglichen Inhalt. Beende die Antwort, ohne JSON zu senden.
  3. Wenn kein Buch diese _id hat, antworte mit dem Statuscode 404 und einer Fehlermeldung, zum Beispiel { "error": "No such book" }. Wenn du dasselbe Buch ein zweites Mal löschst, wird also ebenfalls der Statuscode 404 zurückgegeben, weil es bereits entfernt wurde. Probiere es aus: Sende GET /books und kopiere Emmas _id. Sende DELETE /books/<Emma's _id>: Du erhältst den Statuscode 204 und einen leeren Inhalt. Sende dieselbe Anfrage erneut: Du erhältst den Statuscode 404. Sende GET /books/<Emma's _id>: Du erhältst ebenfalls den Statuscode 404. Sende GET /books: Du erhältst nur Dune und Kindred, und der Tab „Data“ zeigt zwei Bücher an. Drücke „Spielen“, damit Emma wieder hinzugefügt wird.

Probier es selbst

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

// Bei jedem Fehler wird { error: message } zurückgegeben.
function sendError(res, status, message) {
    res.status(status).json({ error: message });
}

// Die :id als ObjectId oder null, nachdem bei einer ungültigen id mit 400 geantwortet wurde.
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');
});

Alle Lektionen in Datenbanken mit MongoDB

Übe selbstständig: Express-Playground