Update-Operatoren
Teil des Abschnitts Datenbanken mit MongoDB der Node.js-Journey von Coddy. Lektion 15 von 29.
Das Hinzufügen einer Kopie oder eines Tags sollte ein Buch direkt ändern, ohne es zu lesen, in JavaScript zu ändern und zurückzuschreiben.
$inc addiert eine Zahl zu einem Feld und beginnt bei 0, wenn das Feld fehlt. $push hängt einen Wert an ein Array-Feld an und erstellt das Array, wenn es fehlt. Ein Update kann mehrere Operatoren enthalten:
await players.updateOne(
{ name: 'Ada' },
{ $inc: { wins: 1 }, $push: { badges: 'streak' } }
);Die Datenbank wendet die Änderung selbst an, sodass zwei Anfragen zum selben Zeitpunkt beide gezählt werden. $set passt hier nicht: Es ersetzt das gesamte badges-Array durch den Wert, den du ihm gibst.
Aufgabe
EinfachDas Regal zählt, wie viele Exemplare jedes Buches du besitzt, und Leser können Bücher mit Tags versehen. Beide Änderungen erfolgen direkt in der Datenbank, jeweils mit einer einzigen Aktualisierung, ohne das Buch vorher auszulesen.
- Füge in
server.jsPOST /books/:id/copieshinzu. Es benötigt keinen Body. Es addiert 1 zum Feldcopiesdes Buches. Bei einem Buch ohne bisherigescopies-Feld lautet der Wert anschließend"copies": 1. - Füge
POST /books/:id/tagshinzu. Im Body wird ein Tag angegeben, zum Beispiel{ "tag": "classic" }. Die Route fügt den Tag am Ende dertags-Liste des Buches hinzu und behält die bereits vorhandenen Tags bei. Bei einem Buch ohne bisherigestags-Feld lautet der Wert anschließend"tags": ["classic"]. - Beide Routen verwenden bei einer ungültigen ID
parseId, woraufhin sie den Status 400 zurückgeben. Beide antworten mit 404, wenn kein Buch diese_idhat. Andernfalls antworten beide mit Status 200 und dem vollständigen aktualisierten Buch. Nach zwei Exemplaren und den Tagsclassicund dannfavoritesieht Dune so aus:Probiere es aus: Sende{ "_id": "6720a1f4c2b9e81d3a5f0c11", "title": "Dune", "author": "Frank Herbert", "year": 1965, "isbn": "9780441013593", "genre": "scifi", "copies": 2, "tags": ["classic", "favorite"] }GET /booksund kopiere Dunes_id. SendePOST /books/<Dune's _id>/copiesmit einem leeren Body: Du erhältst Dune mit"copies": 1. Sende die Anfrage erneut:"copies": 2. SendePOST /books/<Dune's _id>/tagsmit{ "tag": "classic" }:"tags": ["classic"]. Sende die Anfrage erneut mit{ "tag": "favorite" }:"tags": ["classic", "favorite"]. SendePOST /books/000000000000000000000000/copies: Du erhältst 404.
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.listen(3000, () => {
console.log('Bookshelf is running on port 3000');
});
Alle Lektionen in Datenbanken mit MongoDB
1Dokumente
Ein Buch als DokumentSammlungen und DatenbankenVerbindung zu MongoDB herstellenGespeicherte Dokumente lesenDokumente einfügenEin Dokument findenÜber ObjectId suchenZahlen vergleichenAbfragefilterZurückgegebene Felder auswählenAbfrageergebnisse sortierenDie ersten Ergebnisse behaltenProjektion, Sortierung und LimitÜbe selbstständig: Express-Playground