كيفية استخدام MongoDB + Mongoose مع Node.js - أفضل الممارسات لأجهزة الواجهة الخلفية

يعد MongoDB بلا شك أحد أكثر خيارات قاعدة بيانات NoSQL شيوعًا اليوم. ولديها مجتمع كبير ونظام بيئي.

في هذه المقالة ، سنراجع بعضًا من أفضل الممارسات التي يجب اتباعها عند إعداد MongoDB و Mongoose باستخدام Node.js.

المتطلبات المسبقة لهذه المقالة

هذه المقالة هي واحدة من جزء مسار التعلم الخلفي المشفر ، حيث نبدأ من أساسيات الخلفية ونغطيها بالتفصيل. لذلك أفترض أن لديك بعض الخبرة مع JavaScript (و Node.js) بالفعل.

حاليا نحن هنا:

إذا كانت لديك خبرة قليلة جدًا مع Node.js / JavaScript أو النهاية الخلفية بشكل عام ، فمن المحتمل أن يكون هذا مكانًا جيدًا للبدء. يمكنك أيضًا العثور على دورة تدريبية مجانية على Mongoose + MongoDB + Node.js هنا. دعنا نتعمق.

لماذا تحتاج النمس؟

لفهم سبب حاجتنا إلى Mongoose ، دعنا نفهم كيفية عمل MongoDB (وقاعدة البيانات) على مستوى البنية.

  • لديك خادم قاعدة بيانات (خادم مجتمع MongoDB ، على سبيل المثال)
  • لديك برنامج نصي Node.js قيد التشغيل (كعملية)

يستمع خادم MongoDB إلى مقبس TCP (عادةً) ، ويمكن لعملية Node.js الاتصال به باستخدام اتصال TCP.

ولكن في الجزء العلوي من TCP ، يمتلك MongoDB أيضًا بروتوكوله الخاص لفهم ما يريد العميل بالضبط (عملية Node.js الخاصة بنا) أن تفعله قاعدة البيانات.

بالنسبة لهذا الاتصال ، بدلاً من تعلم الرسائل التي يتعين علينا إرسالها على طبقة TCP ، نقوم بتجريد ذلك بمساعدة برنامج "برنامج تشغيل" يسمى برنامج تشغيل MongoDB في هذه الحالة. يتوفر برنامج تشغيل MongoDB كحزمة npm هنا.

تذكر الآن أن برنامج تشغيل MongoDB هو المسؤول عن توصيل واستخلاص طلبات / استجابات الاتصال ذات المستوى المنخفض منك - ولكن هذا فقط يصل بك إلى حد بعيد كمطور.

نظرًا لأن MongoDB هي قاعدة بيانات غير مخطط لها ، فإنها تمنحك قوة أكثر مما تحتاجه كمبتدئ. المزيد من الطاقة يعني مساحة أكبر لخطأ الأشياء. تحتاج إلى تقليل مساحة سطحك من الأخطاء والأخطاء التي يمكنك القيام بها في التعليمات البرمجية الخاصة بك. أنت بحاجة إلى شيء أكثر.

قابل النمس. Mongoose هو تجريد على برنامج التشغيل MongoDB الأصلي (حزمة npm التي ذكرتها أعلاه).

القاعدة العامة مع التجريدات (بالطريقة التي أفهمها) هي أنه مع كل تجريد تفقد بعض قوة التشغيل منخفضة المستوى. لكن هذا لا يعني بالضرورة أنه سيء. في بعض الأحيان يعزز الإنتاجية 1000x + لأنك لا تحتاج حقًا إلى الوصول الكامل إلى واجهة برمجة التطبيقات الأساسية على أي حال.

هناك طريقة جيدة للتفكير في الأمر وهي أن تقوم من الناحية الفنية بإنشاء تطبيق دردشة في الوقت الفعلي بلغة C و Python.

سيكون مثال Python أسهل وأسرع بكثير بالنسبة لك كمطور لتطبيقه بإنتاجية أعلى.

قد يكون C أكثر كفاءة ، لكنه سيأتي بتكلفة ضخمة في الإنتاجية / سرعة التطوير / الأخطاء / الأعطال. بالإضافة إلى ذلك ، لا تحتاج في معظم الأحيان إلى الحصول على الطاقة C التي تمنحك لتنفيذ مآخذ الويب.

وبالمثل ، مع Mongoose ، يمكنك تحديد مساحة السطح الخاصة بك للوصول إلى مستوى أدنى من واجهة برمجة التطبيقات ، ولكن يمكنك فتح الكثير من المكاسب المحتملة و DX الجيد.

كيفية توصيل Mongoose + MongoDB

أولاً ، دعنا نرى سريعًا كيف يجب عليك الاتصال بقاعدة بيانات MongoDB في عام 2020 باستخدام Mongoose:

mongoose.connect(DB_CONNECTION_STRING, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false })

يتأكد تنسيق الاتصال هذا من أنك تستخدم محلل URL الجديد من Mongoose ، وأنك لا تستخدم أي ممارسات مهملة. يمكنك قراءة كل رسائل الإيقاف هذه بالتفصيل هنا إذا أردت.

كيفية إجراء عمليات النمس

دعنا الآن نمضي قدمًا ونناقش العمليات بسرعة مع Mongoose ، وكيف يجب عليك إجراؤها.

يمنحك Mongoose خيارات لأمرين:

  1. الاستعلام المستند إلى المؤشر
  2. استعلام جلب كامل

الاستعلام المستند إلى المؤشر

يعني الاستعلام المستند إلى المؤشر أنك تعمل مع سجل واحد في كل مرة أثناء إحضار مجموعة واحدة أو مجموعة من المستندات في وقت واحد من قاعدة البيانات. هذه طريقة فعالة للعمل بكميات ضخمة من البيانات في بيئة ذاكرة محدودة.

تخيل أنه يتعين عليك تحليل مستندات بحجم إجمالي يبلغ 10 جيجابايت على خادم سحابي بسعة 1 جيجابايت / 1 نقطة. لا يمكنك إحضار المجموعة بأكملها لأن ذلك لن يتناسب مع نظامك. المؤشر هو خيار جيد (والوحيد؟) هنا.

الاستعلام عن الجلب الكامل

هذا هو نوع الاستعلام حيث تحصل على الاستجابة الكاملة لاستعلامك دفعة واحدة. بالنسبة للجزء الأكبر ، هذا هو ما ستستخدمه. لذلك ، سنركز في الغالب على هذه الطريقة هنا.

كيفية استخدام نماذج النمس

النماذج هي القوة العظمى للنمس. إنها تساعدك على فرض قواعد "المخطط" وتوفر تكاملًا سلسًا لرمز العقدة الخاص بك في استدعاءات قاعدة البيانات.

الخطوة الأولى هي تحديد نموذج جيد:

import mongoose from 'mongoose' const CompletedSchema = new mongoose.Schema( { type: { type: String, enum: ['course', 'classroom'], required: true }, parentslug: { type: String, required: true }, slug: { type: String, required: true }, userid: { type: String, required: true } }, { collection: 'completed' } ) CompletedSchema.index({ slug: 1, userid: 1 }, { unique: true }) const model = mongoose.model('Completed', CompletedSchema) export default model 

هذا مثال تم اقتطاعه مباشرة من قاعدة بيانات التشفير. بعض الأشياء الشيقة التي يجب أن تلاحظها هنا:

  1. حاول الاحتفاظ required: trueبجميع الحقول المطلوبة. يمكن أن يكون هذا بمثابة توفير كبير للألم بالنسبة لك إذا لم تستخدم نظام فحص ثابت مثل TypeScript لمساعدتك في أسماء الخصائص الصحيحة أثناء إنشاء كائن. بالإضافة إلى أن التحقق المجاني رائع للغاية أيضًا.
  2. تحديد الفهارس والحقول الفريدة. uniqueيمكن أيضًا إضافة الخاصية داخل المخطط. الفهارس موضوع واسع ، لذا لن أتعمق هنا. ولكن على نطاق واسع يمكنهم حقًا مساعدتك في تسريع استفساراتك كثيرًا.
  3. تحديد اسم المجموعة بشكل صريح. على الرغم من أن Mongoose يمكن أن يعطي تلقائيًا اسمًا للمجموعة بناءً على اسم النموذج ( Completedهنا ، على سبيل المثال) ، فإن هذا يمثل الكثير من التجريد في رأيي. يجب أن تعرف على الأقل أسماء قواعد البيانات والمجموعات في قاعدة البيانات الخاصة بك.
  4. تقييد القيم إذا استطعت باستخدام التعدادات

كيفية إجراء عمليات CRUD

CRUD يعني C reate، R هيئة البيئة، U pdate و D ذف. هذه هي الخيارات الأساسية الأربعة التي يمكنك من خلالها إجراء أي نوع من معالجة البيانات في قاعدة البيانات. دعنا نرى بسرعة بعض الأمثلة على هذه العمليات.

عملية الإنشاء

هذا يعني ببساطة إنشاء سجل جديد في قاعدة بيانات. دعنا نستخدم النموذج الذي حددناه أعلاه لإنشاء سجل:

try { const res = await CompletedSchema.create(record) } catch(error) { console.error(error) // handle the error }

مرة أخرى ، بعض المؤشرات هنا:

  1. استخدام الانتظار غير المتزامن بدلاً من عمليات الاسترجاعات (لطيفة على العيون ، لا فائدة من الأداء الرائد على هذا النحو)
  2. استخدم كتل try-catch حول الاستعلامات لأن استعلامك يمكن أن يفشل لعدد من الأسباب (سجل مكرر ، قيمة غير صحيحة ، وما إلى ذلك)

عملية القراءة

هذا يعني قراءة القيم الموجودة من قاعدة البيانات. الأمر بسيط تمامًا كما يبدو ، ولكن هناك بعض المشاكل التي يجب أن تعرفها مع النمس:

const res = await CompletedSchema.find(info).lean()
  1. هل يمكنك رؤية lean()استدعاء الوظيفة هناك؟ إنه مفيد للغاية للأداء. بشكل افتراضي ، يعالج Mongoose المستند (المستندات) المرتجع من قاعدة البيانات ويضيف طرقها السحرية عليها (على سبيل المثال .save)
  2. عند استخدام .lean()، يقوم Mongoose بإرجاع كائنات JSON عادية بدلاً من الذاكرة ومستندات الموارد الثقيلة. يجعل الاستعلامات أسرع وأقل تكلفة على وحدة المعالجة المركزية الخاصة بك أيضًا.
  3. ومع ذلك ، يمكنك حذف .lean()إذا كنت تفكر بالفعل في تحديث البيانات (سنرى ذلك بعد ذلك)

عملية التحديث

إذا كان لديك بالفعل مستند Mongoose معك (بدون إطلاق النار عليه .lean()) ، فيمكنك ببساطة المضي قدمًا وتعديل خاصية الكائن وحفظها باستخدام object.save():

const doc = await CompletedSchema.findOne(info) doc.slug = 'something-else' await doc.save()

تذكر أنه يوجد هنا استدعائين لقاعدة البيانات. الأول قيد التشغيل findOneوالثاني قيد التشغيل doc.save.

إذا استطعت ، يجب عليك دائمًا تقليل عدد الطلبات التي تصل إلى قاعدة البيانات (لأنك إذا كنت تقارن الذاكرة والشبكة والقرص ، فستكون الشبكة دائمًا أبطأ).

في الحالة الأخرى ، يمكنك استخدام استعلام مثل هذا:

const res = await CompletedSchema.updateOne(, ).lean()

وسيقوم بإجراء مكالمة واحدة لقاعدة البيانات.

عملية الحذف

الحذف واضح أيضًا مع النمس. دعونا نرى كيف يمكنك حذف مستند واحد:

const res = await CompletedSchema.deleteOne()

تمامًا مثل updateOne، deleteOneيقبل أيضًا الوسيطة الأولى كشرط مطابق للمستند.

هناك أيضًا طريقة أخرى تسمى deleteManyوالتي يجب استخدامها فقط عندما تعلم أنك تريد حذف مستندات متعددة.

في أي حالة أخرى ، استخدم دائمًا deleteOneلتجنب عمليات الحذف المتعددة غير المقصودة ، خاصةً عندما تحاول تنفيذ الاستعلامات بنفسك.

استنتاج

كانت هذه المقالة مقدمة بسيطة لعالم Mongoose و MongoDB لمطوري Node.js.

إذا كنت قد استمتعت بهذه المقالة ، فيمكنك تصعيد لعبتك أكثر كمطور باتباع مسار التعلم الخلفي المشفر. لا تتردد في التواصل معي على Twitter للحصول على أي تعليقات!