Menu
CoddyTech

Güncelleme Operatörleri

Coddy'nin Node.js Journey'sinin MongoDB ile Veritabanları bölümünün bir parçası. Ders 15 / 29.

Bir kopya veya etiket eklemek, kitabı okumadan, JavaScript'te değiştirip yeniden yazmadan yerinde değiştirmelidir.

$inc, bir alana sayı ekler; alan yoksa 0'dan başlar. $push, bir dizi alanına değer ekler; alan yoksa diziyi oluşturur. Tek bir güncelleme birkaç işleç içerebilir:

await players.updateOne(
    { name: 'Ada' },
    { $inc: { wins: 1 }, $push: { badges: 'streak' } }
);

Değişikliği veritabanı kendisi uygular, bu yüzden aynı anda yapılan iki isteğin ikisi de sayılır. $set burada uygun değildir: badges dizisinin tamamını verdiğiniz değerle değiştirir.

challenge icon

Görev

Kolay

Kitaplık, sahip olduğunuz her kitabın kaç kopyası olduğunu sayar ve okuyucular kitaplara etiket ekleyebilir. Her iki değişiklik de kitabı önce okumadan, veritabanının içinde tek bir güncellemeyle gerçekleşir.

  1. server.js dosyasına POST /books/:id/copies ekleyin. İstek gövdesi gerekmez. Kitabın copies alanına 1 ekler. Henüz copies alanı olmayan bir kitabın değeri "copies": 1 olur.
  2. POST /books/:id/tags ekleyin. İstek gövdesinde bir etiket belirtilir; örneğin { "tag": "classic" }. Rota, etiketi kitabın tags listesinin sonuna ekler ve listedeki mevcut etiketleri korur. Henüz tags alanı olmayan bir kitabın değeri "tags": ["classic"] olur.
  3. Her iki rota da geçersiz bir kimlik için parseId kullanır ve 400 yanıtı verir. Belirtilen _id değerine sahip bir kitap yoksa her iki rota da 404 yanıtı verir. Aksi hâlde her ikisi de 200 durum kodu ve güncellenmiş kitabın tamamıyla yanıt verir. İki kopya ve önce classic, ardından favorite etiketleri eklendikten sonra Dune şöyle görünür:
    { "_id": "6720a1f4c2b9e81d3a5f0c11", "title": "Dune", "author": "Frank Herbert", "year": 1965, "isbn": "9780441013593", "genre": "scifi", "copies": 2, "tags": ["classic", "favorite"] }
    Deneyin: GET /books isteği gönderin ve Dune'un _id değerini kopyalayın. Boş bir istek gövdesiyle POST /books/<Dune's _id>/copies isteği gönderin: "copies": 1 olan Dune yanıtını alırsınız. İsteği tekrar gönderin: "copies": 2. { "tag": "classic" } gövdesiyle POST /books/<Dune's _id>/tags isteği gönderin: "tags": ["classic"]. Bu kez { "tag": "favorite" } gövdesiyle tekrar gönderin: "tags": ["classic", "favorite"]. POST /books/000000000000000000000000/copies isteği gönderin: 404 yanıtı alırsınız.

Kendin dene

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

// Her hata { error: message } biçiminde yanıt verir.
function sendError(res, status, message) {
    res.status(status).json({ error: message });
}

// :id değerini ObjectId olarak döndürür; geçersiz bir id için 400 yanıtı verdikten sonra null döndürür.
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');
});

MongoDB ile Veritabanları bölümündeki tüm dersler

Kendi başına pratik yap: Express playground