1. نظرة عامة
الأهداف
في مختبر الرموز هذا ، ستنشئ تطبيق ويب لتوصية مطعم مدعوم من Cloud Firestore .
ماذا ستتعلم
- اقرأ البيانات واكتبها إلى Cloud Firestore من تطبيق ويب
- استمع إلى التغييرات في بيانات Cloud Firestore في الوقت الفعلي
- استخدم مصادقة Firebase وقواعد الأمان لتأمين بيانات Cloud Firestore
- اكتب استعلامات Cloud Firestore المعقدة
ماذا ستحتاج
قبل البدء في مختبر الرموز هذا ، تأكد من أنك قمت بتثبيت:
2. إنشاء مشروع Firebase وإعداده
أنشئ مشروع Firebase
- في وحدة تحكم Firebase ، انقر على إضافة مشروع ، ثم قم بتسمية مشروع Firebase FriendlyEats .
تذكر معرّف المشروع لمشروع Firebase الخاص بك.
- انقر فوق إنشاء مشروع .
يستخدم التطبيق الذي سننشئه بعض خدمات Firebase المتاحة على الويب:
- مصادقة Firebase لتحديد المستخدمين بسهولة
- Cloud Firestore لحفظ البيانات المنظمة على السحابة والحصول على إشعار فوري عند تحديث البيانات
- استضافة Firebase لاستضافة أصولك الثابتة وخدمتها
بالنسبة لمعمل الشفرات هذا ، قمنا بالفعل بتكوين استضافة Firebase. ومع ذلك ، بالنسبة إلى Firebase Auth و Cloud Firestore ، سنرشدك خلال تكوين الخدمات وتمكينها باستخدام وحدة تحكم Firebase.
تمكين المصادقة المجهولة
على الرغم من أن المصادقة ليست محور تركيز مختبر الرموز هذا ، فمن المهم أن يكون لديك شكل من أشكال المصادقة في تطبيقنا. سنستخدم تسجيل الدخول المجهول - مما يعني أنه سيتم تسجيل دخول المستخدم بصمت دون أن يُطلب منه ذلك.
ستحتاج إلى تمكين تسجيل الدخول المجهول.
- في وحدة تحكم Firebase ، حدد موقع قسم الإنشاء في التنقل الأيسر.
- انقر فوق المصادقة ، ثم انقر فوق علامة التبويب طريقة تسجيل الدخول (أو انقر هنا للانتقال مباشرة إلى هناك).
- قم بتمكين موفر تسجيل الدخول المجهول ، ثم انقر فوق حفظ .
سيسمح هذا للتطبيق بتسجيل دخول المستخدمين بصمت عند وصولهم إلى تطبيق الويب. لا تتردد في قراءة وثائق المصادقة المجهولة لمعرفة المزيد.
تفعيل Cloud Firestore
يستخدم التطبيق Cloud Firestore لحفظ معلومات المطعم وتقييماته وتلقيها.
ستحتاج إلى تمكين Cloud Firestore. في قسم إنشاء وحدة تحكم Firebase ، انقر فوق قاعدة بيانات Firestore . انقر على إنشاء قاعدة بيانات في جزء Cloud Firestore.
تتحكم قواعد الأمان في الوصول إلى البيانات في Cloud Firestore. سنتحدث أكثر عن القواعد لاحقًا في مختبر الرموز هذا ، لكننا نحتاج أولاً إلى تعيين بعض القواعد الأساسية على بياناتنا للبدء. في علامة التبويب "القواعد" في وحدة تحكم Firebase ، أضف القواعد التالية ثم انقر فوق "نشر" .
service cloud.firestore { match /databases/{database}/documents { match /{document=**} { // // WARNING: These rules are insecure! We will replace them with // more secure rules later in the codelab // allow read, write: if request.auth != null; } } }
تقيد القواعد المذكورة أعلاه الوصول إلى البيانات للمستخدمين الذين قاموا بتسجيل الدخول ، مما يمنع المستخدمين غير المصادق عليهم من القراءة أو الكتابة. هذا أفضل من السماح بالوصول العام ولكنه لا يزال بعيدًا عن الأمان ، وسنعمل على تحسين هذه القواعد لاحقًا في مختبر الرموز.
3. احصل على نموذج التعليمات البرمجية
استنساخ مستودع GitHub من سطر الأوامر:
git clone https://github.com/firebase/friendlyeats-web
يجب استنساخ نموذج الكود في دليل 📁 friendlyeats-web
. من الآن فصاعدًا ، تأكد من تشغيل جميع أوامرك من هذا الدليل:
cd friendlyeats-web
قم باستيراد تطبيق المبتدئين
باستخدام IDE (WebStorm ، Atom ، Sublime ، Visual Studio Code ...) افتح أو استورد دليل الويب 📁 friendlyeats-web
. يحتوي هذا الدليل على رمز البداية لمعمل الرموز والذي يتكون من تطبيق توصيات مطعم غير وظيفي بعد. سنجعله عمليًا خلال مختبر الرموز هذا ، لذا ستحتاج إلى تعديل التعليمات البرمجية في هذا الدليل قريبًا.
4. قم بتثبيت واجهة سطر أوامر Firebase
تتيح لك واجهة سطر أوامر Firebase (CLI) خدمة تطبيق الويب الخاص بك محليًا ونشر تطبيق الويب الخاص بك على Firebase Hosting.
- قم بتثبيت CLI عن طريق تشغيل الأمر npm التالي:
npm -g install firebase-tools
- تحقق من تثبيت CLI بشكل صحيح عن طريق تشغيل الأمر التالي:
firebase --version
تأكد من أن إصدار Firebase CLI هو v7.4.0 أو إصدار أحدث.
- قم بتفويض Firebase CLI عن طريق تشغيل الأمر التالي:
firebase login
لقد أعددنا قالب تطبيق الويب لسحب تهيئة تطبيقك لاستضافة Firebase من الدليل المحلي والملفات الخاصة بتطبيقك. ولكن للقيام بذلك ، نحتاج إلى ربط تطبيقك بمشروع Firebase.
- تأكد من وصول سطر الأوامر إلى الدليل المحلي لتطبيقك.
- اربط تطبيقك بمشروع Firebase عن طريق تشغيل الأمر التالي:
firebase use --add
- عند المطالبة ، حدد معرف المشروع الخاص بك ، ثم امنح مشروع Firebase اسمًا مستعارًا.
يكون الاسم المستعار مفيدًا إذا كانت لديك بيئات متعددة (إنتاج ، مرحلة ، إلخ). ومع ذلك ، بالنسبة لمعمل الرموز هذا ، دعنا نستخدم الاسم default
.
- اتبع التعليمات المتبقية في سطر الأوامر الخاص بك.
5. قم بتشغيل الخادم المحلي
نحن على استعداد لبدء العمل بالفعل على تطبيقنا! لنقم بتشغيل تطبيقنا محليًا!
- قم بتشغيل أمر Firebase CLI التالي:
firebase emulators:start --only hosting
- يجب أن يعرض سطر الأوامر الاستجابة التالية:
hosting: Local server: http://localhost:5000
نحن نستخدم محاكي Firebase Hosting لخدمة تطبيقنا محليًا. يجب أن يكون تطبيق الويب متاحًا الآن من http: // localhost: 5000 .
- افتح التطبيق الخاص بك على http: // localhost: 5000 .
من المفترض أن ترى نسختك من FriendlyEats التي تم توصيلها بمشروع Firebase.
اتصل التطبيق تلقائيًا بمشروع Firebase الخاص بك وقام بتسجيل دخولك بصمت كمستخدم مجهول.
6. كتابة البيانات إلى Cloud Firestore
في هذا القسم ، سنكتب بعض البيانات إلى Cloud Firestore حتى نتمكن من ملء واجهة المستخدم للتطبيق. يمكن القيام بذلك يدويًا عبر وحدة تحكم Firebase ، لكننا سنفعل ذلك في التطبيق نفسه لإثبات كتابة Cloud Firestore الأساسية.
نموذج البيانات
يتم تقسيم بيانات Firestore إلى مجموعات ومستندات وحقول ومجموعات فرعية. سنخزن كل مطعم كمستند في مجموعة عالية المستوى تسمى restaurants
.
لاحقًا ، سنخزن كل تعليق في مجموعة فرعية تسمى ratings
تحت كل مطعم.
أضف المطاعم إلى Firestore
كائن النموذج الرئيسي في تطبيقنا هو مطعم. دعنا نكتب بعض التعليمات البرمجية التي تضيف مستند مطعم إلى مجموعة restaurants
.
- من الملفات التي تم تنزيلها ، افتح
scripts/FriendlyEats.Data.js
. - ابحث عن الوظيفة
FriendlyEats.prototype.addRestaurant
. - استبدل الوظيفة بأكملها بالكود التالي.
FriendlyEats.Data.js
FriendlyEats.prototype.addRestaurant = function(data) { var collection = firebase.firestore().collection('restaurants'); return collection.add(data); };
يضيف الرمز أعلاه مستندًا جديدًا إلى مجموعة restaurants
. تأتي بيانات المستند من كائن JavaScript عادي. نقوم بذلك عن طريق الحصول أولاً على مرجع إلى restaurants
مجموعة Cloud Firestore ثم add
البيانات.
دعونا نضيف المطاعم!
- ارجع إلى تطبيق FriendlyEats في متصفحك وقم بتحديثه.
- انقر فوق إضافة بيانات وهمية .
سيقوم التطبيق تلقائيًا بإنشاء مجموعة عشوائية من عناصر المطاعم ، ثم استدعاء وظيفة addRestaurant
الخاصة بك. ومع ذلك ، لن ترى البيانات في تطبيق الويب الفعلي الخاص بك لأننا ما زلنا بحاجة إلى تنفيذ استرداد البيانات (القسم التالي من مخطط الشفرة).
إذا انتقلت إلى علامة التبويب Cloud Firestore في وحدة تحكم Firebase ، فيجب أن ترى الآن مستندات جديدة في مجموعة restaurants
!
تهانينا ، لقد كتبت للتو بيانات إلى Cloud Firestore من تطبيق ويب!
في القسم التالي ، ستتعلم كيفية استرداد البيانات من Cloud Firestore وعرضها في تطبيقك.
7. عرض البيانات من Cloud Firestore
في هذا القسم ، ستتعلم كيفية استرداد البيانات من Cloud Firestore وعرضها في تطبيقك. الخطوتان الأساسيتان هما إنشاء استعلام وإضافة مستمع لقطة. سيتم إخطار هذا المستمع بجميع البيانات الموجودة التي تطابق الاستعلام وسيتلقى تحديثات في الوقت الفعلي.
أولاً ، دعنا ننشئ الاستعلام الذي سيخدم قائمة المطاعم الافتراضية غير المصفاة.
- ارجع إلى ملف
scripts/FriendlyEats.Data.js
. - ابحث عن الوظيفة
FriendlyEats.prototype.getAllRestaurants
. - استبدل الوظيفة بأكملها بالكود التالي.
FriendlyEats.Data.js
FriendlyEats.prototype.getAllRestaurants = function(renderer) { var query = firebase.firestore() .collection('restaurants') .orderBy('avgRating', 'desc') .limit(50); this.getDocumentsInQuery(query, renderer); };
في الكود أعلاه ، نقوم بإنشاء استعلام يسترد ما يصل إلى 50 مطعمًا من مجموعة restaurants
ذات المستوى الأعلى المسماة ، والتي يتم ترتيبها حسب متوسط التصنيف (حاليًا جميعهم صفر). بعد أن أعلنا عن هذا الاستعلام ، قمنا بتمريره إلى طريقة getDocumentsInQuery()
المسؤولة عن تحميل البيانات وعرضها.
سنفعل ذلك عن طريق إضافة مستمع لقطة.
- ارجع إلى ملف
scripts/FriendlyEats.Data.js
. - ابحث عن الوظيفة
FriendlyEats.prototype.getDocumentsInQuery
. - استبدل الوظيفة بأكملها بالكود التالي.
FriendlyEats.Data.js
FriendlyEats.prototype.getDocumentsInQuery = function(query, renderer) { query.onSnapshot(function(snapshot) { if (!snapshot.size) return renderer.empty(); // Display "There are no restaurants". snapshot.docChanges().forEach(function(change) { if (change.type === 'removed') { renderer.remove(change.doc); } else { renderer.display(change.doc); } }); }); };
في الكود أعلاه ، سيقوم query.onSnapshot
بتشغيل رد الاتصال الخاص به في كل مرة يحدث فيها تغيير في نتيجة الاستعلام.
- في المرة الأولى ، يتم تشغيل رد الاتصال بمجموعة النتائج الكاملة للاستعلام - مما يعني مجموعة
restaurants
بأكملها من Cloud Firestore. ثم يمرر جميع المستندات الفردية إلى وظيفةrenderer.display
. - عند حذف مستند ،
change.type
يساويremoved
. لذلك في هذه الحالة ، سنقوم باستدعاء وظيفة تزيل المطعم من واجهة المستخدم.
الآن بعد أن قمنا بتنفيذ كلتا الطريقتين ، قم بتحديث التطبيق وتحقق من أن المطاعم التي رأيناها سابقًا في وحدة تحكم Firebase أصبحت الآن مرئية في التطبيق. إذا أكملت هذا القسم بنجاح ، فإن تطبيقك يقوم الآن بقراءة البيانات وكتابتها باستخدام Cloud Firestore!
مع تغير قائمة المطاعم الخاصة بك ، سيستمر هذا المستمع في التحديث تلقائيًا. حاول الذهاب إلى وحدة تحكم Firebase وحذف مطعم يدويًا أو تغيير اسمه - سترى التغييرات تظهر على موقعك على الفور!
8. الحصول على () البيانات
حتى الآن ، أوضحنا كيفية استخدام onSnapshot
لاسترداد التحديثات في الوقت الفعلي ؛ ومع ذلك ، هذا ليس دائمًا ما نريده. في بعض الأحيان يكون من المنطقي جلب البيانات مرة واحدة فقط.
سنرغب في تنفيذ طريقة يتم تشغيلها عندما ينقر المستخدم على مطعم معين في تطبيقك.
- ارجع إلى ملفك
scripts/FriendlyEats.Data.js
. - ابحث عن الوظيفة
FriendlyEats.prototype.getRestaurant
. - استبدل الوظيفة بأكملها بالكود التالي.
FriendlyEats.Data.js
FriendlyEats.prototype.getRestaurant = function(id) { return firebase.firestore().collection('restaurants').doc(id).get(); };
بعد تنفيذ هذه الطريقة ، ستتمكن من عرض صفحات كل مطعم. ما عليك سوى النقر فوق أحد المطاعم في القائمة وسترى صفحة تفاصيل المطعم:
في الوقت الحالي ، لا يمكنك إضافة تقييمات لأننا ما زلنا بحاجة إلى إضافة تقييمات لاحقًا في مختبر الرموز.
9. فرز البيانات وتصفيتها
يعرض تطبيقنا حاليًا قائمة المطاعم ، ولكن لا توجد طريقة للمستخدم للتصفية بناءً على احتياجاته. في هذا القسم ، ستستخدم الاستعلام المتقدم في Cloud Firestore لتمكين التصفية.
فيما يلي مثال على استعلام بسيط لجلب جميع مطاعم Dim Sum
:
var filteredQuery = query.where('category', '==', 'Dim Sum')
كما يوحي اسمها ، فإن طريقة where()
ستجعل استعلامنا يقوم بتنزيل أعضاء المجموعة فقط الذين تفي حقولهم بالقيود التي وضعناها. في هذه الحالة ، سيتم تنزيل المطاعم التي تكون category
Dim Sum
فقط.
في تطبيقنا ، يمكن للمستخدم سلسلة فلاتر متعددة لإنشاء استعلامات محددة ، مثل "بيتزا في سان فرانسيسكو" أو "المأكولات البحرية في لوس أنجلوس مرتبة حسب الشعبية".
سننشئ طريقة تؤدي إلى إنشاء استعلام يقوم بتصفية مطاعمنا بناءً على معايير متعددة يختارها مستخدمونا.
- ارجع إلى ملفك
scripts/FriendlyEats.Data.js
. - ابحث عن الوظيفة
FriendlyEats.prototype.getFilteredRestaurants
. - استبدل الوظيفة بأكملها بالكود التالي.
FriendlyEats.Data.js
FriendlyEats.prototype.getFilteredRestaurants = function(filters, renderer) { var query = firebase.firestore().collection('restaurants'); if (filters.category !== 'Any') { query = query.where('category', '==', filters.category); } if (filters.city !== 'Any') { query = query.where('city', '==', filters.city); } if (filters.price !== 'Any') { query = query.where('price', '==', filters.price.length); } if (filters.sort === 'Rating') { query = query.orderBy('avgRating', 'desc'); } else if (filters.sort === 'Reviews') { query = query.orderBy('numRatings', 'desc'); } this.getDocumentsInQuery(query, renderer); };
يضيف الكود أعلاه عدة عوامل تصفية where
وعبارة orderBy
واحدة لبناء استعلام مركب بناءً على مدخلات المستخدم. سيؤدي استعلامنا الآن إلى إرجاع المطاعم التي تطابق متطلبات المستخدم فقط.
قم بتحديث تطبيق FriendlyEats في متصفحك ، ثم تحقق من أنه يمكنك التصفية حسب السعر والمدينة والفئة. أثناء الاختبار ، سترى أخطاء في وحدة تحكم JavaScript في متصفحك تبدو كالتالي:
The query requires an index. You can create it here: https://console.firebase.google.com/project/project-id/database/firestore/indexes?create_composite=...
تعود هذه الأخطاء إلى أن Cloud Firestore يتطلب فهارس لمعظم الاستعلامات المركبة. يؤدي طلب الفهارس على الاستعلامات إلى إبقاء Cloud Firestore سريعًا على نطاق واسع.
سيؤدي فتح الرابط من رسالة الخطأ إلى فتح واجهة مستخدم إنشاء الفهرس تلقائيًا في وحدة تحكم Firebase مع ملء المعلمات الصحيحة. في القسم التالي ، سنقوم بكتابة ونشر الفهارس المطلوبة لهذا التطبيق.
10. نشر الفهارس
إذا لم نرغب في استكشاف كل مسار في تطبيقنا واتباع كل رابط من روابط إنشاء الفهرس ، فيمكننا بسهولة نشر العديد من الفهارس مرة واحدة باستخدام Firebase CLI.
- في الدليل المحلي الذي تم تنزيله لتطبيقك ، ستجد ملف
firestore.indexes.json
.
يصف هذا الملف جميع الفهارس اللازمة لجميع مجموعات المرشحات الممكنة.
firestore.indexes.json
{ "indexes": [ { "collectionGroup": "restaurants", "queryScope": "COLLECTION", "fields": [ { "fieldPath": "city", "order": "ASCENDING" }, { "fieldPath": "avgRating", "order": "DESCENDING" } ] }, ... ] }
- انشر هذه الفهارس باستخدام الأمر التالي:
firebase deploy --only firestore:indexes
بعد بضع دقائق ، ستصبح الفهارس نشطة وستختفي رسائل الخطأ.
11. كتابة البيانات في المعاملة
في هذا القسم ، سنضيف قدرة المستخدمين على إرسال التعليقات إلى المطاعم. حتى الآن ، كانت جميع كتاباتنا ذرية وبسيطة نسبيًا. إذا أخطأ أي منهم ، فمن المحتمل أن نطالب المستخدم بإعادة المحاولة أو سيعيد تطبيقنا الكتابة تلقائيًا.
سيحتوي تطبيقنا على العديد من المستخدمين الذين يرغبون في إضافة تصنيف لمطعم ، لذلك سنحتاج إلى تنسيق العديد من عمليات القراءة والكتابة. يجب أولاً تقديم التقييم نفسه ، ثم يلزم تحديث count
تقييمات المطعم average rating
. إذا فشل أحدهما دون الآخر ، فإننا نترك في حالة غير متسقة حيث لا تتطابق البيانات الموجودة في أحد أجزاء قاعدة البيانات الخاصة بنا مع البيانات الموجودة في جزء آخر.
لحسن الحظ ، يوفر Cloud Firestore وظائف المعاملات التي تتيح لنا إجراء عمليات قراءة وكتابة متعددة في عملية ذرية واحدة ، مما يضمن بقاء بياناتنا متسقة.
- ارجع إلى ملفك
scripts/FriendlyEats.Data.js
. - ابحث عن الوظيفة
FriendlyEats.prototype.addRating
. - استبدل الوظيفة بأكملها بالكود التالي.
FriendlyEats.Data.js
FriendlyEats.prototype.addRating = function(restaurantID, rating) { var collection = firebase.firestore().collection('restaurants'); var document = collection.doc(restaurantID); var newRatingDocument = document.collection('ratings').doc(); return firebase.firestore().runTransaction(function(transaction) { return transaction.get(document).then(function(doc) { var data = doc.data(); var newAverage = (data.numRatings * data.avgRating + rating.rating) / (data.numRatings + 1); transaction.update(document, { numRatings: data.numRatings + 1, avgRating: newAverage }); return transaction.set(newRatingDocument, rating); }); }); };
في الكتلة أعلاه ، نقوم بتشغيل معاملة لتحديث القيم الرقمية avgRating
وعدد numRatings
في مستند المطعم. في الوقت نفسه ، نضيف rating
الجديد إلى المجموعة الفرعية ratings
.
12. تأمين بياناتك
في بداية مختبر الرموز هذا ، قمنا بتعيين قواعد أمان التطبيق لدينا لفتح قاعدة البيانات بالكامل لأي قراءة أو كتابة. في تطبيق حقيقي ، نرغب في وضع قواعد أكثر دقة لمنع الوصول إلى البيانات غير المرغوب فيها أو تعديلها.
- في قسم إنشاء وحدة تحكم Firebase ، انقر فوق قاعدة بيانات Firestore .
- انقر فوق علامة التبويب "القواعد" في قسم Cloud Firestore (أو انقر هنا للانتقال مباشرةً إلى هناك).
- استبدل الإعدادات الافتراضية بالقواعد التالية ، ثم انقر على نشر .
قواعد firestore
rules_version = '2'; service cloud.firestore { // Determine if the value of the field "key" is the same // before and after the request. function unchanged(key) { return (key in resource.data) && (key in request.resource.data) && (resource.data[key] == request.resource.data[key]); } match /databases/{database}/documents { // Restaurants: // - Authenticated user can read // - Authenticated user can create/update (for demo purposes only) // - Updates are allowed if no fields are added and name is unchanged // - Deletes are not allowed (default) match /restaurants/{restaurantId} { allow read: if request.auth != null; allow create: if request.auth != null; allow update: if request.auth != null && (request.resource.data.keys() == resource.data.keys()) && unchanged("name"); // Ratings: // - Authenticated user can read // - Authenticated user can create if userId matches // - Deletes and updates are not allowed (default) match /ratings/{ratingId} { allow read: if request.auth != null; allow create: if request.auth != null && request.resource.data.userId == request.auth.uid; } } } }
تقيد هذه القواعد الوصول لضمان قيام العملاء بإجراء تغييرات آمنة فقط. على سبيل المثال:
- يمكن لتحديثات مستند المطعم فقط تغيير التصنيفات ، وليس الاسم أو أي بيانات أخرى غير قابلة للتغيير.
- لا يمكن إنشاء التقييمات إلا إذا كان معرّف المستخدم يطابق المستخدم الذي سجّل الدخول ، مما يمنع الانتحال.
بدلاً من استخدام وحدة تحكم Firebase ، يمكنك استخدام Firebase CLI لنشر القواعد في مشروع Firebase الخاص بك. يحتوي ملف firestore.rules في دليل العمل الخاص بك بالفعل على القواعد المذكورة أعلاه. لنشر هذه القواعد من نظام الملفات المحلي لديك (بدلاً من استخدام وحدة تحكم Firebase) ، يمكنك تشغيل الأمر التالي:
firebase deploy --only firestore:rules
13. الخلاصة
في مختبر الرموز هذا ، تعلمت كيفية إجراء عمليات القراءة والكتابة الأساسية والمتقدمة باستخدام Cloud Firestore ، بالإضافة إلى كيفية تأمين الوصول إلى البيانات باستخدام قواعد الأمان. يمكنك العثور على الحل الكامل في مستودع quickstarts-js .
لمعرفة المزيد حول Cloud Firestore ، تفضل بزيارة الموارد التالية: