حذف المستندات
جزء من قسم قواعد البيانات باستخدام MongoDB في رحلة Node.js على Coddy. الدرس 8 من 18.
تتطلب إزالة كتاب استدعاءً واحدًا، لكن لا يزال على الخادم إخبار العميل ما إذا كان هناك كتاب لإزالته.
تزيل deleteOne(filter) أول مستند مطابق، وتُرجع { deletedCount }: القيمة 1 إذا أزالت مستندًا، و0 إذا لم يطابق شيء. ويُرجع الحذف الناجح 204 No Content، وهي حالة لا تتضمن متنًا، ويُرسل عبر res.status(204).end().
const result = await sessions.deleteOne({ token });
if (result.deletedCount === 0) {
// لم تكن هناك جلسة تحمل ذلك الرمز
}لا ينبغي أن تنجح إزالة المعرّف نفسه مرتين. في المرة الثانية لن يتبقى شيء، وينبغي أن يتلقى العميل استجابة 404.
التحدي
سهل- يحذف
DELETE /books/:idالكتاب، ويردّ برمز204من دون محتوى. - يؤدي المعرّف غير المعروف إلى ردّ برمز
404، لذا فإن إرسالDELETEمرة ثانية للكتاب نفسه يؤدي إلى الردّ بالرمز ذاته أيضًا.
احذف كتابًا، ثم أرسل طلب DELETE نفسه مرة أخرى، وبعد ذلك انظر إلى علامة تبويب البيانات.
جرّب بنفسك
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);
});
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.listen(3000, () => {
console.log('Bookshelf is running on port 3000');
});