Cloud Firestore Web Codelab

จัดทุกอย่างให้เป็นระเบียบอยู่เสมอด้วยคอลเล็กชัน บันทึกและจัดหมวดหมู่เนื้อหาตามค่ากำหนดของคุณ

1. ภาพรวม

เป้าหมาย

ใน Codelab นี้ คุณจะต้องสร้างเว็บแอปแนะนำร้านอาหารที่ขับเคลื่อนโดย Cloud Firestore

img5.png

สิ่งที่คุณจะได้เรียนรู้

  • อ่านและเขียนข้อมูลไปยัง Cloud Firestore จากเว็บแอป
  • รับฟังการเปลี่ยนแปลงในข้อมูล Cloud Firestore แบบเรียลไทม์
  • ใช้การตรวจสอบสิทธิ์ Firebase และกฎความปลอดภัยเพื่อรักษาความปลอดภัยข้อมูล Cloud Firestore
  • เขียนแบบสอบถาม Cloud Firestore ที่ซับซ้อน

สิ่งที่คุณต้องการ

ก่อนเริ่ม Codelab นี้ ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้ง:

  • npm ซึ่งโดยทั่วไปจะมาพร้อมกับ Node.js - แนะนำให้ใช้ Node v8
  • IDE/ตัวแก้ไขข้อความที่คุณเลือก เช่น WebStorm , Atom , VS Code หรือ Sublime

2. สร้างและตั้งค่าโปรเจ็กต์ Firebase

สร้างโปรเจ็กต์ Firebase

  1. ใน คอนโซล Firebase คลิก เพิ่มโปรเจ็ กต์ จากนั้นตั้งชื่อโปรเจ็กต์ Firebase FriendlyEats

จำรหัสโปรเจ็กต์สำหรับโปรเจ็กต์ Firebase ของคุณ

  1. คลิก สร้างโครงการ

แอปพลิเคชันที่เราจะสร้างใช้บริการ Firebase บางอย่างที่มีอยู่บนเว็บ:

  • การ ตรวจสอบสิทธิ์ Firebase เพื่อระบุผู้ใช้ของคุณได้อย่างง่ายดาย
  • Cloud Firestore เพื่อบันทึกข้อมูลที่มีโครงสร้างบน Cloud และรับการแจ้งเตือนทันทีเมื่อมีการอัปเดตข้อมูล
  • Firebase Hosting เพื่อโฮสต์และให้บริการทรัพย์สินแบบคงที่ของคุณ

สำหรับ Codelab นี้ เราได้กำหนดค่าโฮสติ้งของ Firebase แล้ว อย่างไรก็ตาม สำหรับ Firebase Auth และ Cloud Firestore เราจะแนะนำคุณเกี่ยวกับการกำหนดค่าและการเปิดใช้งานบริการต่างๆ โดยใช้คอนโซล Firebase

เปิดใช้งานการตรวจสอบสิทธิ์แบบไม่ระบุชื่อ

แม้ว่าการตรวจสอบความถูกต้องจะไม่ใช่จุดสนใจของ Codelab นี้ แต่สิ่งสำคัญคือต้องมีการตรวจสอบสิทธิ์บางรูปแบบในแอปของเรา เราจะใช้การ เข้าสู่ระบบแบบไม่ระบุชื่อ - หมายความว่าผู้ใช้จะถูกลงชื่อเข้าใช้โดยไม่แจ้งให้ทราบ

คุณจะต้องเปิดใช้งานการ เข้าสู่ระบบแบบไม่ระบุชื่อ

  1. ในคอนโซล Firebase ให้ค้นหาส่วน Build ในการนำทางด้านซ้าย
  2. คลิก การ ตรวจสอบสิทธิ์ จากนั้นคลิกแท็บ วิธีการลงชื่อเข้าใช้ (หรือ คลิกที่นี่ เพื่อไปที่นั่นโดยตรง)
  3. เปิดใช้งานผู้ให้บริการลงชื่อเข้าใช้แบบ ไม่ระบุชื่อ จากนั้นคลิก บันทึก

img7.png

วิธีนี้จะช่วยให้แอปพลิเคชันสามารถลงชื่อเข้าใช้ผู้ใช้ของคุณโดยไม่โต้ตอบเมื่อเข้าถึงเว็บแอป โปรดอ่าน เอกสารการรับรองความถูกต้องแบบไม่ระบุชื่อ เพื่อเรียนรู้เพิ่มเติม

เปิดใช้งาน Cloud Firestore

แอพใช้ Cloud Firestore เพื่อบันทึกและรับข้อมูลร้านอาหารและการให้คะแนน

คุณจะต้องเปิดใช้งาน Cloud Firestore ในส่วน บิล ด์ของคอนโซล Firebase ให้คลิก ฐานข้อมูล Firestore คลิก สร้างฐานข้อมูล ในบานหน้าต่าง Cloud 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;
    }
  }
}

กฎข้างต้นจำกัดการเข้าถึงข้อมูลสำหรับผู้ใช้ที่ลงชื่อเข้าใช้ ซึ่งป้องกันไม่ให้ผู้ใช้ที่ไม่ผ่านการตรวจสอบสิทธิ์อ่านหรือเขียน ซึ่งดีกว่าการอนุญาตให้เข้าถึงแบบสาธารณะ แต่ยังห่างไกลจากความปลอดภัย เราจะปรับปรุงกฎเหล่านี้ใน Codelab ในภายหลัง

3. รับโค้ดตัวอย่าง

โคลนที่ เก็บ GitHub จากบรรทัดคำสั่ง:

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

โค้ดตัวอย่างควรถูกโคลนไว้ในไดเร็กทอรี friendlyeats-web จากนี้ไป ตรวจสอบให้แน่ใจว่าได้เรียกใช้คำสั่งทั้งหมดของคุณจากไดเร็กทอรีนี้:

cd friendlyeats-web

นำเข้าแอพเริ่มต้น

การใช้ IDE ของคุณ (WebStorm, Atom, Sublime, Visual Studio Code...) เปิดหรือนำเข้าไดเร็กทอรี 📁 friendlyeats-web ไดเร็กทอรีนี้มีโค้ดเริ่มต้นสำหรับ Codelab ซึ่งประกอบด้วยแอปแนะนำร้านอาหารที่ยังใช้งานไม่ได้ เราจะทำให้มันทำงานตลอดทั้ง Codelab นี้ ดังนั้นคุณจะต้องแก้ไขโค้ดในไดเร็กทอรีนั้นเร็วๆ นี้

4. ติดตั้งอินเทอร์เฟซบรรทัดคำสั่ง Firebase

Firebase Command Line Interface (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 Hosting จากไดเรกทอรีและไฟล์ในเครื่องของแอป แต่ในการดำเนินการนี้ เราจำเป็นต้องเชื่อมโยงแอปของคุณกับโปรเจ็กต์ 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 Hosting เพื่อให้บริการแอปของเราในเครื่อง เว็บแอปควรจะพร้อมใช้งานจาก http://localhost:5000

  1. เปิดแอปของคุณที่ http://localhost:5000

คุณควรเห็นสำเนาของ FriendlyEats ซึ่งเชื่อมต่อกับโปรเจ็กต์ Firebase ของคุณ

แอปได้เชื่อมต่อกับโปรเจ็กต์ Firebase ของคุณโดยอัตโนมัติและลงชื่อเข้าใช้ให้คุณในฐานะผู้ใช้ที่ไม่ระบุชื่อ

img2.png

6. เขียนข้อมูลไปยัง Cloud Firestore

ในส่วนนี้ เราจะเขียนข้อมูลบางส่วนไปยัง Cloud Firestore เพื่อให้เราสามารถเติม UI ของแอปได้ สามารถทำได้ด้วยตนเองผ่าน คอนโซล Firebase แต่เราจะทำในแอปเองเพื่อสาธิตการเขียน Cloud 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 ธรรมดา เราทำสิ่งนี้โดยรับการอ้างอิงถึง restaurants คอลเลกชั่น Cloud Firestore ก่อน จากนั้นจึง add ข้อมูล

มาเพิ่มร้านอาหารกันเถอะ!

  1. กลับไปที่แอพ FriendlyEats ในเบราว์เซอร์แล้วรีเฟรช
  2. คลิก เพิ่มข้อมูลจำลอง

แอปจะสร้างชุดออบเจ็กต์ร้านอาหารแบบสุ่มโดยอัตโนมัติ จากนั้นเรียกใช้ฟังก์ชัน addRestaurant ของคุณ อย่างไรก็ตาม คุณจะยังไม่เห็นข้อมูลในเว็บแอปจริงของคุณ เนื่องจากเรายังต้องใช้การ ดึง ข้อมูล (ส่วนถัดไปของ Codelab)

หากคุณไปที่ แท็บ Cloud Firestore ในคอนโซล Firebase ตอนนี้คุณควรเห็นเอกสารใหม่ในคอลเลกชั่น restaurants !

img6.png

ขอแสดงความยินดี คุณเพิ่งเขียนข้อมูลไปยัง Cloud Firestore จากเว็บแอป!

ในส่วนถัดไป คุณจะได้เรียนรู้วิธีดึงข้อมูลจาก Cloud Firestore และแสดงข้อมูลในแอปของคุณ

7. แสดงข้อมูลจาก Cloud Firestore

ในส่วนนี้ คุณจะได้เรียนรู้วิธีดึงข้อมูลจาก Cloud Firestore และแสดงข้อมูลในแอปของคุณ ขั้นตอนสำคัญสองขั้นตอนคือการสร้างคิวรีและเพิ่มตัวฟังสแน็ปช็อต Listener นี้จะได้รับแจ้งข้อมูลที่มีอยู่ทั้งหมดที่ตรงกับการสืบค้นและจะได้รับการอัปเดตแบบเรียลไทม์

ขั้นแรก ให้สร้างแบบสอบถามที่จะให้บริการตามค่าเริ่มต้นของรายชื่อร้านอาหารที่ไม่ผ่านการกรอง

  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 ทั้งหมดจาก Cloud Firestore จากนั้นจะส่งเอกสารทั้งหมดไปยังฟังก์ชัน renderer.display
  • เมื่อเอกสารถูกลบ change.type จะเท่ากับ removed ในกรณีนี้ เราจะเรียกฟังก์ชันที่ลบร้านอาหารออกจาก UI

ตอนนี้เราได้ใช้ทั้งสองวิธีแล้ว ให้รีเฟรชแอปและตรวจสอบว่าร้านอาหารที่เราเห็นก่อนหน้านี้ในคอนโซล Firebase มองเห็นได้ในแอปแล้ว หากคุณทำส่วนนี้เสร็จเรียบร้อยแล้ว แสดงว่าแอปของคุณกำลังอ่านและเขียนข้อมูลด้วย Cloud Firestore!

เมื่อรายชื่อร้านอาหารของคุณเปลี่ยนไป ผู้ฟังรายนี้จะคอยอัปเดตโดยอัตโนมัติ ลองไปที่คอนโซล Firebase และลบร้านอาหารด้วยตนเองหรือเปลี่ยนชื่อ - คุณจะเห็นการเปลี่ยนแปลงปรากฏขึ้นบนเว็บไซต์ของคุณทันที!

img5.png

8. รับ () data

จนถึงตอนนี้ เราได้แสดงวิธีใช้ 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

ในตอนนี้ คุณไม่สามารถเพิ่มการให้คะแนนได้ เนื่องจากเรายังต้องใช้การเพิ่มการให้คะแนนในภายหลังใน Codelab

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 ทำงานได้รวดเร็วในวงกว้าง

การเปิดลิงก์จากข้อความแสดงข้อผิดพลาดจะเปิด UI การสร้างดัชนีในคอนโซล 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. รักษาความปลอดภัยข้อมูลของคุณ

ในช่วงเริ่มต้นของ Codelab นี้ เราตั้งกฎความปลอดภัยของแอปให้เปิดฐานข้อมูลโดยสมบูรณ์สำหรับการอ่านหรือเขียนใดๆ ในแอปพลิเคชันจริง เราต้องการตั้งค่ากฎที่ละเอียดมากขึ้น เพื่อป้องกันการเข้าถึงหรือแก้ไขข้อมูลที่ไม่ต้องการ

  1. ในส่วน บิล ด์ของคอนโซล Firebase ให้คลิก ฐานข้อมูล Firestore
  2. คลิกแท็บ กฎ ในส่วน Cloud Firestore (หรือ คลิกที่นี่ เพื่อไปที่นั่นโดยตรง)
  3. แทนที่ค่าเริ่มต้นด้วยกฎต่อไปนี้ จากนั้นคลิก เผยแพร่

firestore.rules

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;
      }
    }
  }
}

กฎเหล่านี้จำกัดการเข้าถึงเพื่อให้แน่ใจว่าลูกค้าทำการเปลี่ยนแปลงอย่างปลอดภัยเท่านั้น ตัวอย่างเช่น:

  • การอัปเดตเอกสารร้านอาหารสามารถเปลี่ยนได้เฉพาะการให้คะแนน ไม่สามารถเปลี่ยนชื่อหรือข้อมูลอื่นๆ ที่ไม่เปลี่ยนรูปได้
  • สามารถสร้างการให้คะแนนได้ก็ต่อเมื่อ ID ผู้ใช้ตรงกับผู้ใช้ที่ลงชื่อเข้าใช้ ซึ่งจะป้องกันการปลอมแปลง

คุณสามารถใช้ Firebase CLI เพื่อปรับใช้กฎกับโปรเจ็กต์ Firebase แทนการใช้คอนโซล Firebase ไฟล์ firestore.rules ในไดเร็กทอรีการทำงานของคุณมีกฎจากด้านบนอยู่แล้ว ในการปรับใช้กฎเหล่านี้จากระบบไฟล์ในเครื่องของคุณ (แทนที่จะใช้คอนโซล Firebase) คุณต้องเรียกใช้คำสั่งต่อไปนี้:

firebase deploy --only firestore:rules

13. บทสรุป

ใน Codelab นี้ คุณได้เรียนรู้วิธีดำเนินการอ่านและเขียนขั้นพื้นฐานและขั้นสูงด้วย Cloud Firestore รวมถึงวิธีรักษาความปลอดภัยในการเข้าถึงข้อมูลด้วยกฎความปลอดภัย คุณสามารถค้นหาโซลูชันแบบเต็มได้ในที่ เก็บ quickstarts-js

หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับ Cloud Firestore ให้ไปที่แหล่งข้อมูลต่อไปนี้: