التحديث والحذف في MongoDB
المكتبة تتغير باستمرار: كتاب أصبح متاحاً، وسعر ارتفع، وتصنيف جديد أُضيف، وكتب قديمة خرجت من الخدمة. في هذا الدرس الأخير ستتعلم تعديل المستندات وحذفها. وستكتشف أن MongoDB تعطيك أدوات دقيقة جداً: تستطيع تعديل حقل واحد، أو زيادة رقم، أو إضافة عنصر لمصفوفة، دون لمس باقي المستند.
updateOne مع $set
Section titled “updateOne مع $set”db.books.updateOne( { title: 'البرمجة للمبتدئين' }, { $set: { available: true, price: 110 } }){ acknowledged: true, insertedId: null, matchedCount: 1, modifiedCount: 1, upsertedCount: 0}updateOne تأخذ:
- الفلتر: أي مستند تعدّل، بنفس صيغة
find. - التعديل: ماذا تغيّر، عبر معاملات التحديث.
$set تضع قيمة جديدة للحقول المذكورة فقط، وتترك باقي المستند كما هو. وإذا كان الحقل غير موجود، تضيفه.
قراءة الرد:
matchedCount: كم مستنداً طابق الفلتر.modifiedCount: كم مستنداً تغيّر فعلاً. قد يكون أقل من المطابق إذا كانت القيم الجديدة مساوية للقديمة.
معاملات التحديث
Section titled “معاملات التحديث”$inc: زيادة رقم
db.books.updateOne({ title: 'رحلة إلى القمر' }, { $inc: { pages: 20 } })الصفحات كانت 180، فأصبحت 200. و $inc بقيمة سالبة تُنقص، مثل { $inc: { stock: -1 } } عند بيع نسخة. ميزتها أنها آمنة عندما يعدّل عدة مستخدمين نفس الرقم في نفس اللحظة.
$push: إضافة عنصر لمصفوفة
db.books.updateOne({ title: 'رحلة إلى القمر' }, { $push: { genres: 'أطفال' } })db.books.findOne({ title: 'رحلة إلى القمر' }, { genres: 1, _id: 0 }){ genres: [ 'خيال علمي', 'مغامرات', 'أطفال' ] }ولحذف عنصر من مصفوفة: $pull. ولإضافة عنصر فقط إن لم يكن موجوداً: $addToSet، مفيدة لمنع تكرار التصنيفات.
$unset: حذف حقل
db.books.updateOne({ title: 'رحلة إلى القمر' }, { $unset: { notes: '' } })الحقل notes اختفى من المستند تماماً. (القيمة '' لا تهم، فالمهم اسم الحقل.)
| المعامل | الوظيفة |
|---|---|
$set |
تعيين قيمة حقل |
$unset |
حذف حقل |
$inc |
زيادة رقم أو إنقاصه |
$push و $pull |
إضافة عنصر لمصفوفة أو حذفه منها |
$addToSet |
إضافة لمصفوفة دون تكرار |
updateMany
Section titled “updateMany”لتعديل كل المستندات المطابقة. مثلاً، زيادة 10 جنيهات على كل كتب «دار المعرفة»:
db.books.updateMany({ 'publisher.name': 'دار المعرفة' }, { $inc: { price: 10 } }){ acknowledged: true, insertedId: null, matchedCount: 2, modifiedCount: 2, upsertedCount: 0}كتابان طابقا وتغيّرا: «أسرار البحار» أصبح 100، و«عالم الروبوتات» أصبح 160.
الخطأ الشائع: نسيان المعامل
Section titled “الخطأ الشائع: نسيان المعامل”ماذا لو كتبت التعديل دون $set؟
db.books.updateOne({ title: 'حكايات جدتي' }, { price: 50 })Update document requires atomic operatorsرفض MongoDB العملية، لأن updateOne تحتاج معاملات مثل $set. وهذه حماية مفيدة: في أنظمة قديمة، كان هذا الخطأ يستبدل المستند كله بـ { price: 50 } فتضيع كل باقي الحقول! وإذا أردت فعلاً استبدال المستند كاملاً، فهناك أمر صريح لذلك: replaceOne.
upsert: حدّث أو أضف
Section titled “upsert: حدّث أو أضف”ماذا لو لم يطابق الفلتر أي مستند؟
db.books.updateOne({ title: 'كتاب غير موجود' }, { $set: { price: 1 } })الرد فيه matchedCount: 0، ولم يحدث شيء. لكن أحياناً تريد: «حدّث المستند إن وُجد، وإلا أنشئه». هذا هو upsert:
db.books.updateOne( { title: 'علوم الفضاء' }, { $set: { author: 'كريم نبيل', year: 2024, available: true } }, { upsert: true }){ acknowledged: true, insertedId: ObjectId('6af3b81b51809dda14a5123b'), matchedCount: 0, modifiedCount: 0, upsertedCount: 1}لم يجد كتاباً بهذا العنوان، فأنشأ مستنداً جديداً يجمع الفلتر والتعديل معاً. مفيد جداً لعدادات الزيارات وإعدادات المستخدمين.
الحذف: deleteOne و deleteMany
Section titled “الحذف: deleteOne و deleteMany”db.books.deleteOne({ title: 'علوم الفضاء' }){ acknowledged: true, deletedCount: 1 }ولحذف كل الكتب الأقدم من 2019:
db.books.deleteMany({ year: { $lt: 2019 } }){ acknowledged: true, deletedCount: 2 }حُذف «أسرار البحار» (2018) و«حكايات جدتي» (2015)، وبقيت 3 كتب.
جرّب بنفسك
Section titled “جرّب بنفسك”على مجموعة الكتب:
- اجعل كل الكتب غير المتاحة متاحة بـ
updateManyو$set. - أضف حقل
ratingsلكتاب، ثم أضف إليه تقييمين بـ$push. - أنقص سعر كتاب 15 جنيهاً بـ
$inc. - احذف حقلاً من كتاب بـ
$unset. - استخدم
upsertلكتاب جديد، ثم نفّذ نفس الأمر مرة ثانية، وقارن الردين. - احذف الكتب التي عدد صفحاتها أقل من 100، بعد التأكد بـ
countDocuments.
أخطاء شائعة
Section titled “أخطاء شائعة”- نسيان $set: خطأ
Update document requires atomic operators. - updateOne حين تقصد الكل: تعدّل أول مستند مطابق فقط. استخدم
updateMany. - عدم قراءة الرد:
matchedCount: 0يعني أن الفلتر لم يطابق شيئاً، غالباً بسبب خطأ إملائي في القيمة أو اسم الحقل.
اختبر نفسك
Section titled “اختبر نفسك”سؤال
أي تعديل يزيد عدد النسخ stock بمقدار 5؟
$inc تضيف القيمة إلى الرقم الحالي، أما $set فتستبدله بـ 5.
سؤال
ماذا يفعل الخيار upsert: true إذا لم يطابق الفلتر أي مستند؟
upsert تعني «حدّث إن وُجد، وإلا أضف»، فينشئ مستنداً جديداً عند عدم المطابقة.
الخلاصة
Section titled “الخلاصة”updateOneوupdateManyتأخذان فلتراً وتعديلاً بمعاملات مثل$setو$inc.$pushو$pullو$addToSetللمصفوفات، و$unsetلحذف حقل.matchedCountوmodifiedCountتخبرانك بما حدث فعلاً.upsert: trueيحدّث أو ينشئ، وreplaceOneلاستبدال المستند كاملاً.deleteOneوdeleteManyللحذف، وdeleteMany({})تحذف الكل.