Cloud Firestore Web Codelab

1. نظرة عامة

الأهداف

في هذا codelab، عليك بناء تطبيق ويب مطعم توصية مدعوم من الغيمة Firestore .

img5.png

ماذا ستتعلم

  • قراءة البيانات وكتابتها إلى Cloud Firestore من تطبيق ويب
  • استمع إلى التغييرات في بيانات Cloud Firestore في الوقت الفعلي
  • استخدم مصادقة Firebase وقواعد الأمان لتأمين بيانات Cloud Firestore
  • اكتب استعلامات Cloud Firestore المعقدة

ماذا ستحتاج

قبل البدء في مختبر الرموز هذا ، تأكد من أنك قمت بتثبيت:

2. إنشاء مشروع Firebase وإعداده

أنشئ مشروع Firebase

  1. في وحدة التحكم Firebase ، انقر فوق المشروع إضافة، ثم قم بتسمية FriendlyEats مشروع Firebase.

تذكر معرّف المشروع لمشروع Firebase الخاص بك.

  1. انقر فوق إنشاء المشروع.

يستخدم التطبيق الذي سننشئه بعض خدمات Firebase المتاحة على الويب:

  • مصادقة Firebase التعرف بسهولة للمستخدمين
  • سحابة Firestore لحفظ البيانات المهيكلة على سحابة والحصول على إشعار حظة عندما يتم تحديث البيانات
  • استضافة Firebase لاستضافة وخدمة الأصول الثابتة الخاصة بك

بالنسبة إلى مختبر الرموز هذا ، قمنا بالفعل بتكوين استضافة Firebase. ومع ذلك ، بالنسبة إلى Firebase Auth و Cloud Firestore ، سنرشدك خلال التكوين وتمكين الخدمات باستخدام وحدة تحكم Firebase.

تمكين المصادقة المجهولة

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

ستحتاج إلى تمكين تسجيل الدخول المجهول.

  1. في وحدة تحكم Firebase، موقع المقطع البناء في التنقل اليمنى.
  2. انقر فوق المصادقة، ثم انقر فوق علامة التبويب في طريقة (أو انقر هنا للذهاب مباشرة هناك).
  3. تمكين مجهول تسجيل الدخول موفر، ثم انقر فوق حفظ.

img7.png

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

تفعيل Cloud Firestore

يستخدم التطبيق Cloud Firestore لحفظ معلومات المطعم وتقييماته وتلقيها.

ستحتاج إلى تمكين Cloud Firestore. في قسم بناء وحدة Firebase، وانقر فوق قاعدة بيانات Firestore. انقر فوق إنشاء قاعدة بيانات في الجزء سحابة 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. احصل على نموذج التعليمات البرمجية

استنساخ مستودع جيثب من سطر الأوامر:

git clone https://github.com/firebase/friendlyeats-web

يجب أن يكون تم استنساخ نموذج التعليمات البرمجية في 📁 friendlyeats-web الدليل. من الآن فصاعدًا ، تأكد من تشغيل جميع أوامرك من هذا الدليل:

cd friendlyeats-web

قم باستيراد تطبيق المبتدئين

استخدام IDE الخاص بك (WebStorm، الذرة، سبحانه، فيجوال ستوديو الرمز ...) مفتوحة أو استيراد 📁 friendlyeats-web الدليل. يحتوي هذا الدليل على رمز البداية لمعمل الرموز والذي يتكون من تطبيق توصيات مطعم غير وظيفي بعد. سنجعله عمليًا خلال مختبر الرموز هذا ، لذا ستحتاج إلى تعديل التعليمات البرمجية في هذا الدليل قريبًا.

4. قم بتثبيت واجهة سطر أوامر Firebase

تتيح لك واجهة سطر أوامر Firebase (CLI) خدمة تطبيق الويب محليًا ونشر تطبيق الويب الخاص بك على Firebase Hosting.

  1. قم بتثبيت CLI عن طريق تشغيل الأمر npm التالي:
npm -g install firebase-tools
  1. تحقق من تثبيت CLI بشكل صحيح عن طريق تشغيل الأمر التالي:
firebase --version

تأكد من أن إصدار Firebase CLI هو v7.4.0 أو إصدار أحدث.

  1. قم بتفويض Firebase CLI عن طريق تشغيل الأمر التالي:
firebase login

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

  1. تأكد من وصول سطر الأوامر إلى الدليل المحلي لتطبيقك.
  2. اربط تطبيقك بمشروع Firebase عن طريق تشغيل الأمر التالي:
firebase use --add
  1. عند المطالبة، حدد اسم المستخدم الخاص بك المشروع، ثم إعطاء المشروع Firebase الخاص بك اسم مستعار.

يكون الاسم المستعار مفيدًا إذا كانت لديك بيئات متعددة (إنتاج ، مرحلة ، إلخ). ومع ذلك، لهذا codelab، دعونا فقط استخدام الاسم المستعار default .

  1. اتبع التعليمات المتبقية في سطر الأوامر الخاص بك.

5. قم بتشغيل الخادم المحلي

نحن على استعداد لبدء العمل بالفعل على تطبيقنا! لنقم بتشغيل تطبيقنا محليًا!

  1. قم بتشغيل أمر Firebase CLI التالي:
firebase emulators:start --only hosting
  1. يجب أن يعرض سطر الأوامر الاستجابة التالية:
hosting: Local server: http://localhost:5000

نحن نستخدم استضافة Firebase منافس لخدمة التطبيق لدينا محليا. وينبغي أن يكون تطبيق الويب متوفر الآن من HTTP: // المضيف المحلي: 5000 .

  1. فتح التطبيق في HTTP: // المضيف المحلي: 5000 .

يجب أن ترى نسختك من FriendlyEats التي تم توصيلها بمشروع Firebase.

اتصل التطبيق تلقائيًا بمشروع Firebase الخاص بك وقام بتسجيل دخولك بصمت كمستخدم مجهول.

img2.png

6. كتابة البيانات إلى Cloud Firestore

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

نموذج البيانات

يتم تقسيم بيانات Firestore إلى مجموعات ومستندات وحقول ومجموعات فرعية. سنقوم بتخزين كل مطعم كوثيقة في مجموعة المستوى الأعلى يسمى restaurants .

img3.png

وفي وقت لاحق، سنقوم بتخزين كل مراجعة في المجموعة الفرعية ودعا ratings تحت كل مطعم.

img4.png

أضف المطاعم إلى Firestore

كائن النموذج الرئيسي في تطبيقنا هو مطعم. دعونا إرسال بعض التعليمات البرمجية التي تضيف وثيقة مطعم لل restaurants المجموعة.

  1. من الملفات تحميلها، وفتح scripts/FriendlyEats.Data.js .
  2. البحث عن وظيفة FriendlyEats.prototype.addRestaurant .
  3. استبدل الوظيفة بأكملها بالكود التالي.

FriendlyEats.Data.js

FriendlyEats.prototype.addRestaurant = function(data) {
  var collection = firebase.firestore().collection('restaurants');
  return collection.add(data);
};

رمز أعلاه يضيف مستند جديد إلى restaurants المجموعة. تأتي بيانات المستند من كائن JavaScript عادي. ونحن نفعل ذلك عن طريق الحصول على أول إشارة إلى مجموعة الغيمة Firestore restaurants ثم add "جي البيانات.

دعونا نضيف المطاعم!

  1. ارجع إلى تطبيق FriendlyEats في متصفحك وقم بتحديثه.
  2. انقر فوق إضافة بيانات وهمية.

فإن التطبيق تلقائيا توليد مجموعة عشوائية من الأشياء المطاعم، ثم استدعاء الطبيب addRestaurant وظيفة. ومع ذلك، فإنك لن ترى بعد البيانات في التطبيق الفعلي الويب الخاص بك لأننا ما زلنا بحاجة إلى تنفيذ استرداد البيانات (القسم التالي من codelab).

إذا كنت انتقل إلى علامة التبويب سحابة Firestore في وحدة تحكم Firebase، على الرغم من الآن يجب أن نرى وثائق جديدة في restaurants جمع!

img6.png

تهانينا ، لقد كتبت للتو بيانات إلى Cloud Firestore من تطبيق ويب!

في القسم التالي ، ستتعلم كيفية استرداد البيانات من Cloud Firestore وعرضها في تطبيقك.

7. عرض البيانات من Cloud Firestore

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

أولاً ، لنقم ببناء الاستعلام الذي سيخدم قائمة المطاعم الافتراضية التي لم تتم تصفيتها.

  1. العودة الى ملف scripts/FriendlyEats.Data.js .
  2. البحث عن وظيفة FriendlyEats.prototype.getAllRestaurants .
  3. استبدل الوظيفة بأكملها بالكود التالي.

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() الطريقة التي هي المسؤولة عن الشحن وتقديم البيانات.

سنفعل ذلك عن طريق إضافة مستمع لقطة.

  1. العودة الى ملف scripts/FriendlyEats.Data.js .
  2. البحث عن وظيفة FriendlyEats.prototype.getDocumentsInQuery .
  3. استبدل الوظيفة بأكملها بالكود التالي.

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 جمع من الغيمة Firestore. ثم يمر كل الوثائق الفردية إلى renderer.display وظيفة.
  • عند حذف وثيقة، change.type يساوي removed . لذلك في هذه الحالة ، سنقوم باستدعاء وظيفة تزيل المطعم من واجهة المستخدم.

الآن بعد أن قمنا بتنفيذ كلتا الطريقتين ، قم بتحديث التطبيق وتحقق من أن المطاعم التي رأيناها سابقًا في وحدة تحكم Firebase أصبحت الآن مرئية في التطبيق. إذا أكملت هذا القسم بنجاح ، فإن تطبيقك يقوم الآن بقراءة البيانات وكتابتها باستخدام Cloud Firestore!

مع تغير قائمة المطاعم الخاصة بك ، سيستمر هذا المستمع في التحديث تلقائيًا. حاول الذهاب إلى وحدة تحكم Firebase وحذف مطعم يدويًا أو تغيير اسمه - سترى التغييرات تظهر على موقعك على الفور!

img5.png

8. الحصول على () البيانات

حتى الآن، لقد أظهرت كيفية استخدام onSnapshot لاسترداد التحديثات في الوقت الحقيقي؛ ومع ذلك ، هذا ليس دائمًا ما نريده. في بعض الأحيان يكون من المنطقي جلب البيانات مرة واحدة فقط.

سنرغب في تنفيذ طريقة يتم تشغيلها عندما ينقر المستخدم على مطعم معين في تطبيقك.

  1. العودة إلى ملف scripts/FriendlyEats.Data.js .
  2. البحث عن وظيفة FriendlyEats.prototype.getRestaurant .
  3. استبدل الوظيفة بأكملها بالكود التالي.

FriendlyEats.Data.js

FriendlyEats.prototype.getRestaurant = function(id) {
  return firebase.firestore().collection('restaurants').doc(id).get();
};

بعد تنفيذ هذه الطريقة ، ستتمكن من عرض صفحات كل مطعم. ما عليك سوى النقر فوق أحد المطاعم في القائمة وسترى صفحة تفاصيل المطعم:

img1.png

في الوقت الحالي ، لا يمكنك إضافة تقييمات لأننا ما زلنا بحاجة إلى إضافة تقييمات لاحقًا في مختبر الرموز.

9. فرز البيانات وتصفيتها

حاليًا ، يعرض تطبيقنا قائمة المطاعم ، ولكن لا توجد طريقة للمستخدم للتصفية بناءً على احتياجاته. في هذا القسم ، ستستخدم الاستعلام المتقدم في Cloud Firestore لتمكين التصفية.

وإليك مثال استعلام بسيط لجلب جميع Dim Sum المطاعم:

var filteredQuery = query.where('category', '==', 'Dim Sum')

كما يوحي اسمها، where() وطريقة جعل لدينا الاستعلام تحميل فقط لأعضاء المجموعة التي مواجهة القيود التي حددناها المجالات. في هذه الحالة، فإنه سوف فقط تحميل المطاعم حيث category هي Dim Sum .

في تطبيقنا ، يمكن للمستخدم سلسلة فلاتر متعددة لإنشاء استعلامات محددة ، مثل "بيتزا في سان فرانسيسكو" أو "المأكولات البحرية في لوس أنجلوس مرتبة حسب الشعبية".

سننشئ طريقة تؤدي إلى إنشاء استعلام يقوم بتصفية مطاعمنا بناءً على معايير متعددة يختارها مستخدمونا.

  1. العودة إلى ملف scripts/FriendlyEats.Data.js .
  2. البحث عن وظيفة FriendlyEats.prototype.getFilteredRestaurants .
  3. استبدل الوظيفة بأكملها بالكود التالي.

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/.../database/firestore/indexes?create_index=...

تعود هذه الأخطاء إلى أن Cloud Firestore يتطلب فهارس لمعظم الاستعلامات المركبة. يؤدي طلب الفهارس على الاستعلامات إلى إبقاء Cloud Firestore سريعًا على نطاق واسع.

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

10. نشر الفهارس

إذا لم نرغب في استكشاف كل مسار في تطبيقنا واتباع كل رابط من روابط إنشاء الفهرس ، فيمكننا بسهولة نشر العديد من الفهارس مرة واحدة باستخدام Firebase CLI.

  1. في الدليل المحلي تحميل التطبيق الخاص بك، ستجد firestore.indexes.json الملف.

يصف هذا الملف جميع الفهارس اللازمة لجميع مجموعات المرشحات الممكنة.

firestore.indexes.json

{
 "indexes": [
   {
     "collectionGroup": "restaurants",
     "queryScope": "COLLECTION",
     "fields": [
       { "fieldPath": "city", "order": "ASCENDING" },
       { "fieldPath": "avgRating", "order": "DESCENDING" }
     ]
   },

   ...

 ]
}
  1. انشر هذه الفهارس باستخدام الأمر التالي:
firebase deploy --only firestore:indexes

بعد بضع دقائق ، ستصبح الفهارس نشطة وستختفي رسائل الخطأ.

11. كتابة البيانات في المعاملة

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

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

لحسن الحظ ، يوفر Cloud Firestore وظائف المعاملات التي تتيح لنا إجراء عمليات قراءة وكتابة متعددة في عملية ذرية واحدة ، مما يضمن بقاء بياناتنا متسقة.

  1. العودة إلى ملف scripts/FriendlyEats.Data.js .
  2. البحث عن وظيفة FriendlyEats.prototype.addRating .
  3. استبدل الوظيفة بأكملها بالكود التالي.

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. تأمين بياناتك

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

  1. في قسم بناء وحدة Firebase، وانقر فوق قاعدة بيانات Firestore.
  2. انقر فوق علامة التبويب قواعد في قسم سحابة Firestore (أو انقر هنا للذهاب مباشرة هناك).
  3. استبدال الإعدادات الافتراضية للقواعد التالية، ثم انقر فوق نشر.

قواعد 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-شبيبة .

لمعرفة المزيد حول Cloud Firestore ، تفضل بزيارة الموارد التالية: