Menu
CoddyTech

Belgeleri Sayma

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

Bir gösterge paneli sayılara ihtiyaç duyar ve yalnızca dizinin uzunluğunu okumak için her belgeyi yüklemek, veritabanının hepsini göndermesine neden olur.

countDocuments(filter), eşleşen belgelerden hiçbirini göndermeden kaç tane olduklarını söyler. Filtre verilmezse koleksiyonun tamamını sayar.

const open = await tickets.countDocuments({ status: 'open' });
const all = await tickets.countDocuments();

Filtreyi, GET /books uç noktasının yaptığı gibi sorgudan oluştur ve aynı filtreyi sayım işlemine ilet. Filtreyi dikkate almayan bir sayım yanlış soru için doğru sayıyı verir: istemci açık biletleri sormuşken tüm biletleri sayar.

challenge icon

Görev

Kolay

Bir kontrol paneli, kaç kitap ve puanlama olduğunu gösterir. Her belgeyi yüklemek yerine bunları veritabanında sayın.

  1. server.js içinde, // Add GET /stats here. yorumunun altına bir GET /stats rotası ekleyin.
  2. Bu rota 200 durum koduyla ve her koleksiyondaki belge sayısıyla yanıt verir. Başlangıçtaki kitaplar ve hiç puanlama olmadığında sonuç şöyledir:
    { "books": 3, "ratings": 0 }
  3. ?genre=scifi, books sayımının yalnızca bu türdeki kitapları saymasını sağlar. Tür ne olursa olsun ratings her zaman tüm puanlamaları sayar. Deneyin: GET /stats isteğini gönderin: { "books": 3, "ratings": 0 } sonucunu alırsınız. GET /stats?genre=scifi isteğini gönderin: { "books": 2, "ratings": 0 }. GET /stats?genre=poetry isteğini gönderin: { "books": 0, "ratings": 0 }. GET /books yanıtından Dune kitabının _id değerini kopyalayın, ardından PUT /books/<Dune's _id>/ratings isteğini { "user": "ada", "stars": 4 } ile gönderin. GET /stats isteğini tekrar gönderin: { "books": 3, "ratings": 1 }.

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');
const ratings = db.collection('ratings');

await books.createIndex({ isbn: 1 }, { unique: true });
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;
    try {
        await books.insertOne(book);
    } catch (err) {
        if (err.code === 11000) {
            return sendError(res, 409, 'That ISBN is already on the shelf');
        }
        throw err;
    }
    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.post('/books/:id/copies', async (req, res) => {
    const id = parseId(req, res);
    if (!id) return;
    const result = await books.updateOne({ _id: id }, { $inc: { copies: 1 } });
    if (result.matchedCount === 0) {
        return sendError(res, 404, 'No such book');
    }
    res.json(await books.findOne({ _id: id }));
});

app.post('/books/:id/tags', async (req, res) => {
    const id = parseId(req, res);
    if (!id) return;
    const result = await books.updateOne({ _id: id }, { $push: { tags: req.body.tag } });
    if (result.matchedCount === 0) {
        return sendError(res, 404, 'No such book');
    }
    res.json(await books.findOne({ _id: id }));
});

app.delete('/books/:id', async (req, res) => {
    const id = parseId(req, res);
    if (!id) return;
    const result = await books.deleteOne({ _id: id });
    if (result.deletedCount === 0) {
        return sendError(res, 404, 'No such book');
    }
    res.status(204).end();
});

app.put('/books/:id/ratings', async (req, res) => {
    const id = parseId(req, res);
    if (!id) return;
    const { user, stars } = req.body;
    await ratings.updateOne({ bookId: id, user }, { $set: { stars } }, { upsert: true });
    res.json({ user, stars });
});

app.get('/books/:id/ratings', async (req, res) => {
    const id = parseId(req, res);
    if (!id) return;
    res.json(await ratings.find({ bookId: id }).toArray());
});

// GET /stats uç noktasını buraya ekleyin.

app.listen(3000, () => {
    console.log('Bookshelf is running on port 3000');
});
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

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

Kendi başına pratik yap: Express playground