קוד אינטרנט של Cloud Firestore

מטרות

בשנת codelab זו, תוכל לבנות יישום אינטרנט המלצה למסעדה מופעל על ידי קלאוד Firestore .

img5.png

מה תלמד

  • קרא וכתוב נתונים ל- Cloud Firestore מאפליקציית אינטרנט
  • האזן לשינויים בנתוני Cloud Firestore בזמן אמת
  • השתמש בכללי אימות ואבטחה של Firebase לאבטחת נתוני Cloud Firestore
  • כתוב שאילתות מורכבות של Cloud Firestore

מה אתה צריך

לפני שתתחיל ב- codelab זה, ודא שהתקנת:

צור פרויקט Firebase

  1. בשנות ה קונסולת Firebase , לחץ הוסף פרויקט, ולאחר מכן תנו שם FriendlyEats פרויקט Firebase.

זכור את מזהה הפרויקט עבור פרויקט Firebase שלך.

  1. לחץ על צור הפרויקט.

היישום שאנו הולכים לבנות משתמש בכמה שירותי Firebase הזמינים באינטרנט:

  • אימות Firebase בקלות לזהות את המשתמשים שלך
  • ענן Firestore להציל נתונים מובנים ב- Cloud ולקבל הודעה מיידית כאשר הנתונים מתעדכן
  • Firebase אירוח לארח ולשרת נכסים סטטיים שלך

עבור הכרטיסייה הספציפית הזו כבר הגדרנו את Firebase Hosting. עם זאת, עבור Firebase Auth ו- Cloud Firestore, נלווה אותך בתצורת ההפעלה וההפעלה של השירותים באמצעות מסוף Firebase.

אפשר אימות אנונימי

למרות שאימות אינו מוקד הכרטיסייה הזו, חשוב שיהיה איזושהי אימות באפליקציה שלנו. נשתמש התחברות אנונימית - כלומר המשתמש ייחתם בשקט מבלי שתבקש ממנו.

תצטרך לאפשר כניסה אנונימי.

  1. בשנות ה Firebase הקונסולה, לאתר את הקטע לבנות הניווט השמאלי.
  2. לחץ אימות, ולאחר מכן לחץ על כניסת כרטיסיית שיטה (או לחץ כאן כדי לעבור ישירות לשם).
  3. אפשר הכניסה אנונימי ספק, ולאחר מכן לחץ על שמור.

img7.png

זה יאפשר ליישום להיכנס למשתמשים שלך בשקט כאשר הם ניגשים לאפליקציית האינטרנט. אל תהסס לקרוא את תיעוד האימות אנונימי כדי ללמוד עוד.

הפעל את Cloud Firestore

האפליקציה משתמשת ב- Cloud Firestore כדי לשמור ולקבל מידע על מסעדות ודירוגים.

יהיה עליך להפעיל את Cloud Firestore. במקטע בנה של Firebase המסוף, לחץ מסד firestore. לחץ על צור מסד נתונים בחלונית ענן firestore.

הגישה לנתונים ב- Cloud Firestore נשלטת על ידי כללי האבטחה. נדבר יותר על כללים בהמשך codelab זה, אך ראשית עלינו להגדיר כמה כללים בסיסיים בנתונים שלנו כדי להתחיל. ב הכרטיסייה הכללית של קונסולת 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;
    }
  }
}

הכללים לעיל מגבילים את גישת הנתונים למשתמשים שנכנסים לחשבון, מה שמונע ממשתמשים לא מאומתים לקרוא או לכתוב. זה טוב יותר מאשר לאפשר גישה לציבור אך הוא עדיין רחוק מלהיות מאובטח, אנו נשפר את הכללים האלה בהמשך הקודג.

לשבט את מאגר GitHub משורת הפקודה:

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

הקוד לדוגמה היה צריך משובטים לתוך 📁 friendlyeats-web בספרייה. מעתה והלאה, הקפד להפעיל את כל הפקודות שלך מספרייה זו:

cd friendlyeats-web

ייבא את אפליקציית המתנע

באמצעות IDE שלך (WebStorm, Atom, סאבליים, קוד של Visual Studio ...) פתוח או לייבא את 📁 friendlyeats-web בספרייה. ספרייה זו מכילה את קוד ההתחלה של ה- codelab המורכב מאפליקציית המלצות למסעדות שטרם מתפקדת. אנו נהפוך אותו לתפקוד לאורך כל קוד הדף הזה, כך שתצטרך לערוך קוד בספרייה זו בקרוב.

ממשק שורת הפקודה של Firebase (CLI) מאפשר לך לשרת את אפליקציית האינטרנט שלך באופן מקומי ולפרוס את אפליקציית האינטרנט שלך לאירוח Firebase.

  1. התקן את CLI על ידי הפעלת הפקודה npm הבאה:
npm -g install firebase-tools
  1. ודא כי ה- CLI הותקן כהלכה על ידי הפעלת הפקודה הבאה:
firebase --version

וודא שגירסת ה- CLI של Firebase היא גרסה 7.4.0 ואילך.

  1. אשר את CLI של Firebase על ידי הפעלת הפקודה הבאה:
firebase login

הגדרנו את תבנית אפליקציית האינטרנט כדי לשלוף את תצורת האפליקציה שלך לאירוח Firebase מהספרייה והקבצים המקומיים של האפליקציה שלך. אך לשם כך עלינו לשייך את האפליקציה שלך לפרויקט Firebase שלך.

  1. וודא ששורת הפקודה שלך ניגשת לספרייה המקומית של האפליקציה שלך.
  2. שייך את האפליקציה שלך לפרויקט Firebase שלך ​​על ידי הפעלת הפקודה הבאה:
firebase use --add
  1. כשתתבקש, בחר מזהה הפרויקט שלך, ואז לתת פרויקט Firebase שלך בדוי.

כינוי שימושי אם יש לך מספר סביבות (ייצור, בימוי וכו '). עם זאת, עבור codelab זה, בוא פשוט להשתמש בכינוי של default .

  1. בצע את ההוראות הנותרות בשורת הפקודה שלך.

אנחנו מוכנים להתחיל לעבוד על האפליקציה שלנו! בואו להפעיל את האפליקציה שלנו באופן מקומי!

  1. הפעל את הפקודה הבאה של Firebase CLI:
firebase emulators:start --only hosting
  1. שורת הפקודה שלך אמורה להציג את התגובה הבאה:
hosting: Local server: http://localhost:5000

אנו משתמשים אירוח Firebase אמולטור לשרת האפליקציה שלנו מקומית. אפליקציית האינטרנט אמורה להיות זמינה החל http: // localhost: 5000 .

  1. פתח את האפליקציה שלך ב http: // localhost: 5000 .

אתה אמור לראות את העותק שלך של FriendlyEats שהיה מחובר לפרויקט Firebase שלך.

האפליקציה התחברה אוטומטית לפרויקט Firebase שלך ​​ובאופן כניסה נכנסת בשקט כמשתמש אנונימי.

img2.png

בחלק זה נכתוב כמה נתונים ל- Cloud Firestore כדי שנוכל לאכלס את ממשק המשתמש של האפליקציה. ניתן לעשות זאת באופן ידני באמצעות קונסולת Firebase , אבל נצטרך לעשות את זה ב האפליקציה עצם כדי להדגים כתיבה בסיסית הענן firestore.

מודל נתונים

נתוני Firestore מחולקים לאוספים, מסמכים, שדות ואוספי משנה. אנו נאחסן כל מסעדה כמסמך באוסף ברמה העליונה שנקרא restaurants .

img3.png

מאוחר יותר, אנו נאחסן כל הביקורות בתוך subcollection בשם 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 "ing את הנתונים.

נוסיף מסעדות!

  1. חזור לאפליקציית FriendlyEats בדפדפן שלך ורענן אותה.
  2. לחץ להוסיף נתונים מוק.

אפליקציית תפיק אוטומטית קבוצה אקראית של חפצי מסעדות, ואז להתקשר שלך addRestaurant הפונקציה. עם זאת, תוכלו עדיין לא רואה את הנתונים של יישום האינטרנט שלך בפועל, כי אנחנו עדיין צריכים ליישם אחזור נתונים (בחלק הבא של codelab).

אם תנווט כרטיסיית הענן Firestore במסוף Firebase, אם כי, אתה אמור לראות מסמכים חדשים restaurants אוספות!

img6.png

מזל טוב, כתבת כרגע נתונים ל- Cloud Firestore מאפליקציית אינטרנט!

בחלק הבא תלמד כיצד לאחזר נתונים מ- 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

עד כה, הראנו כיצד להשתמש 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

לעת עתה, אינך יכול להוסיף דירוגים מכיוון שעדיין עלינו ליישם הוספת דירוגים מאוחר יותר בתא הקוד.

נכון לעכשיו, האפליקציה שלנו מציגה רשימת מסעדות, אך אין אפשרות למשתמש לסנן בהתאם לצרכיו. בחלק זה תשתמש בשאילתות המתקדמות של 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 עם הפרמטרים הנכונים שממלאים. בחלק הבא נכתוב ונפרס את האינדקסים הדרושים ליישום זה.

אם איננו רוצים לחקור כל נתיב באפליקציה שלנו ולעקוב אחר כל אחד מהקישורים ליצירת אינדקס, נוכל לפרוס בקלות אינדקסים רבים בבת אחת באמצעות ה- CLI של Firebase.

  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

לאחר מספר דקות האינדקסים שלך יהיו פעילים והודעות השגיאה ייעלמו.

בחלק זה נוסיף למשתמשים את היכולת לשלוח ביקורות למסעדות. עד כה כל הכתיבות שלנו היו אטומיות ופשוטות יחסית. אם מישהו מהם טעה, סביר להניח שרק נבקש מהמשתמש לנסות אותם שוב או שהאפליקציה שלנו תנסה לכתוב מחדש באופן אוטומטי.

לאפליקציה שלנו יהיו משתמשים רבים שרוצים להוסיף דירוג למסעדה, לכן נצטרך לתאם קריאות וכתיבה מרובות. ראשית הסקירה עצמה צריכה להגיש, אז את הדירוג של המסעדה 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 subcollection.

בתחילת codelab זה, הגדרנו את כללי האבטחה של האפליקציה שלנו כדי לפתוח את מסד הנתונים לחלוטין לכל קריאה או כתיבה. ביישום אמיתי, נרצה לקבוע כללים הרבה יותר מדויקים כדי למנוע גישה או שינוי בלתי רצויים של נתונים.

  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

בתפקיד קוד זה למדת כיצד לבצע קריאה וכתיבה בסיסיים ומתקדמים באמצעות Cloud Firestore, כמו גם כיצד לאבטח גישה לנתונים בעזרת כללי אבטחה. אתה יכול למצוא את הפתרון המלא של מאגר quickstarts-JS .

למידע נוסף על Cloud Firestore, בקר במשאבים הבאים: