Opérateurs de mise à jour
Fait partie de la section Bases de données avec MongoDB du Journey Node.js de Coddy. Leçon 15 sur 29.
Ajouter une copie ou une étiquette doit modifier un livre directement, sans le lire, le modifier en JavaScript puis le réécrire.
$inc ajoute un nombre à un champ, en partant de 0 lorsque le champ est absent. $push ajoute une valeur à la fin d’un champ tableau, en créant le tableau lorsqu’il est absent. Une mise à jour peut contenir plusieurs opérateurs :
await players.updateOne(
{ name: 'Ada' },
{ $inc: { wins: 1 }, $push: { badges: 'streak' } }
);La base de données applique elle-même la modification, de sorte que deux requêtes effectuées au même moment sont toutes deux prises en compte. $set ne convient pas ici : il remplace tout le tableau badges par la valeur que vous lui donnez.
Défi
FacileLa bibliothèque compte le nombre d’exemplaires de chaque livre que tu possèdes, et les lecteurs peuvent ajouter des étiquettes aux livres. Ces deux modifications s’effectuent dans la base de données, chacune en une seule mise à jour, sans lire le livre au préalable.
- Dans
server.js, ajoutePOST /books/:id/copies. Aucun corps de requête n’est nécessaire. La route ajoute 1 au champcopiesdu livre. Un livre qui n’a pas encore de champcopiesse retrouve avec"copies": 1. - Ajoute
POST /books/:id/tags. Le corps de la requête indique une étiquette, par exemple{ "tag": "classic" }. La route ajoute l’étiquette à la fin de la listetagsdu livre et conserve les étiquettes déjà présentes. Un livre qui n’a pas encore de champtagsse retrouve avec"tags": ["classic"]. - Pour un identifiant invalide, les deux routes utilisent
parseId, qui renvoie le code 400. Elles renvoient toutes deux le code 404 si aucun livre ne possède cet_id. Sinon, elles renvoient toutes deux le statut 200 et le livre entier mis à jour. Après avoir ajouté deux exemplaires et les étiquettesclassic, puisfavorite, Dune ressemble à ceci :Essaie : Envoie{ "_id": "6720a1f4c2b9e81d3a5f0c11", "title": "Dune", "author": "Frank Herbert", "year": 1965, "isbn": "9780441013593", "genre": "scifi", "copies": 2, "tags": ["classic", "favorite"] }GET /bookset copie l’_idde Dune. EnvoiePOST /books/<Dune's _id>/copiesavec un corps vide : tu obtiens Dune avec"copies": 1. Envoie la requête une nouvelle fois :"copies": 2. EnvoiePOST /books/<Dune's _id>/tagsavec{ "tag": "classic" }:"tags": ["classic"]. Envoie-la une nouvelle fois avec{ "tag": "favorite" }:"tags": ["classic", "favorite"]. EnvoiePOST /books/000000000000000000000000/copies: tu obtiens le code 404.
Essayez vous-même
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());
// Chaque erreur renvoie { error: message }.
function sendError(res, status, message) {
res.status(status).json({ error: message });
}
// Le :id sous forme d’ObjectId, ou null après avoir renvoyé 400 pour un id invalide.
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');
});
Toutes les leçons de Bases de données avec MongoDB
1Documents
Un livre comme documentCollections et bases de donnéesSe connecter à MongoDBLire des documents stockésInsérer des documentsTrouver un documentRechercher par ObjectIdComparer des nombresFiltres de requêteChoisir les champs renvoyésTrier les résultats de requêteConserver les premiers résultatsProjection, tri et limite2Modifier les documents
Mettre à jour les documentsOpérateurs de mise à jourEntraînez-vous par vous-même : Playground Express