Menu
CoddyTech

Actualización de documentos

Parte de la sección Bases de datos con MongoDB del Journey de Node.js de Coddy. Lección 14 de 29.

Corregir el año de un libro debería cambiar ese campo y dejar los demás intactos.

updateOne(filter, update) cambia el primer documento que coincide con el filtro. La actualización se compone de operadores: $set escribe los campos que le indicas y conserva todos los demás. Se rechaza un objeto simple sin operadores con el mensaje "Update document requires atomic operators".

const result = await players.updateOne(
    { name: 'Ada' },
    { $set: { score: 120, level: 4 } }
);
result.matchedCount;  // 1 si se encontró un jugador que coincidía, 0 si no se encontró ninguno
result.modifiedCount; // 0 cuando los valores ya eran los mismos

Usa matchedCount, no modifiedCount, para distinguir un documento inexistente de uno que no se modificó. La actualización no devuelve el documento, así que vuelve a leerlo con findOne.

challenge icon

Desafío

Fácil

Un cliente quiere corregir un campo de un libro, como un año incorrecto, sin volver a enviar el libro completo.

  1. En server.js, debajo del comentario // Add PATCH /books/:id here., añade una ruta PATCH /books/:id.
  2. Empieza de la misma manera que empieza ahora GET /books/:id: llama a parseId(req, res). Si el id no es válido, parseId ya ha respondido con 400 y devuelve null, así que detente ahí.
  3. Cambia solo los campos que envía el cuerpo y deja todos los demás como estaban. Un cuerpo { "year": 1966 } cambia el año y nada más.
  4. Si no hay ningún libro con ese _id, responde con el estado 404 y un error, por ejemplo { "error": "No such book" }.
  5. De lo contrario, responde con el estado 200 y el libro completo tal como está almacenado ahora:
    { "_id": "6720a1f4c2b9e81d3a5f0c11", "title": "Dune", "author": "Frank Herbert", "year": 1966, "isbn": "9780441013593", "genre": "scifi" }
    Pruébalo: Envía GET /books y copia el _id de Dune. Vuelve a copiarlo después de cada ejecución, porque cada ejecución genera nuevos id. Envía PATCH /books/ seguido del _id de Dune, con el cuerpo { "year": 1966 }. Obtienes 200 y Dune con "year": 1966, con todos los demás campos sin cambios, y la pestaña Data muestra lo mismo. Envía la misma solicitud otra vez: sigues obteniendo 200, porque el libro existe aunque esta vez no haya cambiado nada. Envía PATCH /books/000000000000000000000000 con { "year": 1966 }: obtienes 404. Envía PATCH /books/42: obtienes 400.

Pruébalo tú mismo

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

// Cada error responde con { error: message }.
function sendError(res, status, message) {
    res.status(status).json({ error: message });
}

// El :id como ObjectId, o null después de responder con 400 si el id no es válido.
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);
});

// Añade PATCH /books/:id aquí.

app.listen(3000, () => {
    console.log('Bookshelf is running on port 3000');
});
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Bases de datos con MongoDB

Practica por tu cuenta: Playground de Express