دليل شامل لـ GridFS: كيفية رفع الملفات والصور إلى MongoDB بسهولة باستخدام Node.js
يُعد تخزين الملفات ميزة أساسية لا غنى عنها في العديد من العمليات عبر أنواع مختلفة من التطبيقات. لطالما سهّل وجود حلول مثل شبكات توصيل المحتوى (CDNs)، التي تُقام غالبًا عبر خيارات سحابية خارجية كخدمات ويب أمازون (Amazon Web Services)، بالإضافة إلى خيارات التخزين المحلية للملفات، بناء هذه الميزة. ومع ذلك، لطالما أثار مفهوم تخزين الملفات مباشرةً في قاعدة البيانات عبر استدعاء واجهة برمجية واحدة (API call) فضولي لبعض الوقت. هنا تحديدًا يبرز دور GridFS.

ربما ليس هو الحل الأمثل دائمًا لتطبيق نظام تخزين الملفات، لكنه يقدم إمكانيات فريدة.
فهم GridFS بتبسيط: ما هو وكيف يعمل؟
تمتلك MongoDB مواصفات خاصة ببرنامج التشغيل (driver specification) لرفع واسترداد الملفات منها، تُعرف باسم GridFS. يتيح لك GridFS تخزين واسترداد الملفات، بما في ذلك تلك التي تتجاوز حد حجم مستند BSON البالغ 16 ميغابايت. يقوم GridFS أساسًا بتقسيم الملف إلى أجزاء متعددة (chunks) تُخزن كمستندات فردية في مجموعتين (collections):
- مجموعة الأجزاء
(chunk collection): تخزن أجزاء المستند الفعلية. - مجموعة الملفات
(file collection): تخزن البيانات الوصفية الإضافية الناتجة(metadata).
يقتصر حجم كل جزء على 255 كيلوبايت. هذا يعني أن الجزء الأخير عادة ما يكون مساويًا أو أقل من 255 كيلوبايت. عند القراءة من GridFS، يقوم برنامج التشغيل بإعادة تجميع جميع الأجزاء حسب الحاجة. وهذا يعني أنه يمكنك قراءة أقسام من الملف وفقًا لنطاق استعلامك، مثل الاستماع إلى جزء من ملف صوتي أو جلب قسم من ملف فيديو.
ملاحظة هامة: يُفضل استخدام GridFS لتخزين الملفات التي تتجاوز عادة حد الحجم البالغ 16 ميغابايت. بالنسبة للملفات الأصغر حجمًا، يوصى باستخدام تنسيق BinData لتخزين الملفات في مستندات فردية. هذا يلخص كيفية عمل GridFS بشكل عام. حان الوقت الآن للخوض في بعض الأكواد العملية ورؤية كيفية تطبيق نظام كهذا.
الانتقال إلى التطبيق العملي: إعداد GridFS باستخدام Node.js
سنستخدم Node.js مع إمكانية الوصول إلى نسخة سحابية من MongoDB لإعدادنا. يمكنك العثور على مستودع الأكواد للتطبيق النموذجي هنا: https://github.com/tarique93102/gridfs-file-storage.
سنركز بشكل كامل على أجزاء الكود التي تتعلق بوظائف GridFS. سنتعلم كيفية إعداده واستخدامه لتخزين الملفات، استرداد ملفات معينة أو جميعها، وحذف ملف معين. لنبدأ إذن.
تهيئة محرك التخزين (Storage Engine)
الحزم المطلوبة لتهيئة المحرك هي multer-gridfs-storage و multer. نستخدم أيضًا وسيط method-override middleware لتمكين عملية حذف الملفات. تُستخدم وحدة npm المسماة crypto لتشفير أسماء الملفات عند تخزينها وقراءتها من قاعدة البيانات. بمجرد تهيئة محرك التخزين باستخدام GridFS، ما عليك سوى استدعائه باستخدام وسيط multer middleware. ثم يتم تمريره إلى المسار (route) المعني الذي ينفذ عمليات تخزين الملفات المختلفة.

تهيئة تدفق GridFS (GridFS Stream)
نقوم بتهيئة تدفق GridFS كما هو موضح في الكود أدناه. التدفق ضروري لقراءة الملفات من قاعدة البيانات، وكذلك للمساعدة في عرض صورة للمتصفح عند الحاجة.

رفع ملف أو صورة واحدة
نُعيد استخدام وسيط الرفع (upload middleware) الذي أنشأناه سابقًا.
ملاحظة: يُستخدم الاسم file كمعامل في upload.single() نظرًا لأن لدينا مفتاحًا يحمل اسمًا مشابهًا يحمل الملف الذي يتم إرساله من العميل.

رفع عدة ملفات أو صور
يمكننا أيضًا رفع عدة ملفات دفعة واحدة. بدلاً من upload.single()، علينا ببساطة استخدام upload.array(<عدد الملفات>). (ملاحظة: العدد الفعلي للملفات المرفوعة يمكن أن يكون أقل من العدد المحدد للملفات.)

جلب جميع الملفات من قاعدة البيانات
باستخدام التدفق الذي تم تهيئته، يمكننا جلب جميع الملفات في قاعدة البيانات المعينة باستخدام gfs.find().toArray(...). بمجرد الحصول على الملفات، نقوم بتحويلها إلى مصفوفة (array) ونرسل الاستجابة.

جلب ملف واحد باسم الملف
من السهل جدًا الاستعلام عن GridFS لملف واحد بناءً على سمة معينة مثل filename. باستخدام تدفق GridFS، يمكنك الاستعلام عن قاعدة البيانات عبر الدالة gfs.find({<أضف الاستعلام هنا>}).

عرض صورة مجلوبة في المتصفح
هذا الجزء أكثر تعقيدًا بعض الشيء، حيث يتعين عليك ليس فقط جلب ملف من قاعدة البيانات، بل أيضًا عرضه كصورة على المتصفح المعني. نقوم بجلب الملف بشكل طبيعي، ولا يوجد تغيير في هذه العملية. ثم بمساعدة الدالة openDownloadStreamByName() على تدفق gfs، يمكننا بسهولة عرض صورة لأنها تُرجع تدفقًا قابلاً للقراءة (readable stream). بعد ذلك، يمكننا استخدام دالة pipe() في JavaScript لتدفق الاستجابة.

حذف ملف معين بواسطة المعرف (ID)
حذف ملف مباشر بنفس القدر. نستخدم دالة التدفق delete() مع المعامل _id للاستعلام عن الملف المعني وحذفه.

هذه هي الوظائف الرئيسية التي يقدمها تصميم محرك التخزين. لقد استفدت من ميزات GridFS التي تمت مناقشتها لإنشاء تطبيق بسيط لرفع الصور. يمكنك التعمق أكثر في الكود في المستودع.
الخلاصة
لقد استغرق مني الأمر بعض الوقت وجهدًا لا بأس به لفهم كيفية استخدام GridFS لمشروع شخصي. ولهذا السبب، أردت التأكد من أن شخصًا آخر على الأقل لن يضطر إلى استثمار نفس القدر من الوقت. ومع ذلك، أوصي باستخدام GridFS بحذر. إنه ليس حلاً سحريًا لجميع مخاوف تخزين الملفات لديك. ومع ذلك، فهو مواصفات رائعة لمعرفتها والوعي بها. إذا كان لديك أي استفسارات أو مخاوف، يمكنك التعليق على المنشور أو التواصل معي عبر LinkedIn (أو منصات التواصل المهني الأخرى). في هذه الأثناء، استمر في البرمجة.
الخلاصة التقنية
يمثل GridFS حلاً قويًا ومرنًا لتحدي تخزين الملفات الكبيرة التي تتجاوز حدود حجم المستندات التقليدية في MongoDB. من خلال استراتيجيته المبتكرة في تقسيم الملفات إلى أجزاء صغيرة وتخزين البيانات الوصفية بشكل منفصل، يوفر GridFS إمكانية إدارة فعالة للمحتوى الثقيل مثل الفيديو والصور عالية الدقة. ومع ذلك، يجب على المطورين تقييم ما إذا كانت هذه الآلية هي الأنسب لحالات استخدامهم؛ فبالنسبة للملفات الصغيرة، قد تكون حلول التخزين المباشر أو استخدام BinData أكثر كفاءة. يبرز المقال بوضوح كيفية دمج GridFS بسلاسة مع بيئة Node.js باستخدام مكتبات مثل multer، مما يجعله خيارًا جذابًا للتطبيقات التي تتطلب مرونة عالية في التعامل مع الملفات ضمن نظام MongoDB البيئي.