Menu
CoddyTech

עדכון מסמכים

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

תיקון השנה של ספר צריך לשנות את השדה הזה בלבד ולהשאיר את שאר השדות ללא שינוי.

updateOne(filter, update) משנה את המסמך הראשון שתואם למסנן. העדכון מורכב מאופרטורים: $set כותב את השדות שמציינים ושומר על כל שאר השדות. אובייקט רגיל ללא אופרטור נדחה עם ההודעה "Update document requires atomic operators".

const result = await players.updateOne(
    { name: 'Ada' },
    { $set: { score: 120, level: 4 } }
);
result.matchedCount;  // 1 אם נמצאה התאמה לשחקן, 0 אם לא נמצאה התאמה
result.modifiedCount; // 0 אם הערכים כבר היו זהים

כדי להבחין בין מסמך חסר למסמך שלא השתנה, יש להשתמש ב-matchedCount, ולא ב-modifiedCount. העדכון לא מחזיר את המסמך, לכן יש לקרוא אותו שוב באמצעות findOne.

challenge icon

אתגר

קל

לקוח רוצה לתקן שדה אחד של ספר, למשל שנה שגויה, בלי לשלוח שוב את הספר כולו.

  1. ב־server.js, מתחת להערה // Add PATCH /books/:id here., הוסף נתיב PATCH /books/:id.
  2. התחל אותו כפי שהנתיב GET /books/:id מתחיל כעת: קרא ל־parseId(req, res). כשהמזהה שגוי, parseId כבר השיבה עם קוד 400 ומחזירה null, לכן עצור שם.
  3. שנה רק את השדות שנשלחים בגוף הבקשה, והשאר כל שדה אחר כפי שהיה. גוף בקשה של { "year": 1966 } משנה את השנה בלבד.
  4. אם אין ספר עם _id הזה, החזר סטטוס 404 ושגיאה, למשל { "error": "No such book" }.
  5. אחרת, החזר סטטוס 200 ואת הספר כולו כפי שהוא מאוחסן כעת:
    { "_id": "6720a1f4c2b9e81d3a5f0c11", "title": "Dune", "author": "Frank Herbert", "year": 1966, "isbn": "9780441013593", "genre": "scifi" }
    נסה זאת: שלח GET /books והעתק את _id של Dune. העתק אותו שוב אחרי כל הפעלה, כי בכל הפעלה מתקבלים מזהים חדשים. שלח PATCH /books/ ואחריו ה־_id של Dune, עם גוף הבקשה { "year": 1966 }. תקבל 200 ואת Dune עם "year": 1966, כאשר כל שאר השדות ללא שינוי, וכך גם מוצג בלשונית Data. שלח שוב את אותה בקשה: עדיין תקבל 200, כי הספר קיים, אף שהפעם לא השתנה דבר. שלח PATCH /books/000000000000000000000000 עם { "year": 1966 }: תקבל 404. שלח PATCH /books/42: תקבל 400.

נסו בעצמכם

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

// הוסיפו כאן PATCH /books/:id.

app.listen(3000, () => {
    console.log('Bookshelf is running on port 3000');
});
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

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

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