เกี่ยวกับ Codelab นี้
1 ภาพรวม
เป้าหมาย
ในโค้ดแล็บนี้ คุณจะได้สร้างแอปแนะนำร้านอาหารที่ใช้ Firestore เป็นแบ็กเอนด์บน iOS ใน Swift คุณจะได้เรียนรู้วิธีต่อไปนี้
- อ่านและเขียนข้อมูลไปยัง Firestore จากแอป iOS
- ฟังการเปลี่ยนแปลงข้อมูล Firestore แบบเรียลไทม์
- ใช้การตรวจสอบสิทธิ์ Firebase และกฎการรักษาความปลอดภัยเพื่อรักษาความปลอดภัยของข้อมูล Firestore
- เขียนการค้นหา Firestore ที่ซับซ้อน
ข้อกำหนดเบื้องต้น
โปรดตรวจสอบว่าคุณได้ติดตั้งสิ่งต่อไปนี้ก่อนเริ่ม Codelab นี้
- Xcode เวอร์ชัน 14.0 (หรือสูงกว่า)
- CocoaPods 1.12.0 (หรือสูงกว่า)
2 รับโปรเจ็กต์ตัวอย่าง
ดาวน์โหลดรหัส
เริ่มต้นด้วยการโคลนโปรเจ็กต์ตัวอย่างและเรียกใช้ pod update
ในไดเรกทอรีโปรเจ็กต์
git clone https://github.com/firebase/friendlyeats-ios cd friendlyeats-ios pod update
เปิด FriendlyEats.xcworkspace
ใน Xcode แล้วเรียกใช้ (Cmd+R) แอปควรคอมไพล์ได้อย่างถูกต้องและขัดข้องทันทีเมื่อเปิดใช้ เนื่องจากไม่มีไฟล์ GoogleService-Info.plist
เราจะแก้ไขในขั้นตอนถัดไป
3 ตั้งค่า Firebase
สร้างโปรเจ็กต์ Firebase
- ลงชื่อเข้าใช้คอนโซล Firebase โดยใช้บัญชี Google
- คลิกปุ่มเพื่อสร้างโปรเจ็กต์ใหม่ แล้วป้อนชื่อโปรเจ็กต์ (เช่น
FriendlyEats
)
- คลิกต่อไป
- หากได้รับแจ้ง ให้อ่านและยอมรับข้อกำหนดของ Firebase แล้วคลิกต่อไป
- (ไม่บังคับ) เปิดใช้ความช่วยเหลือจาก AI ในคอนโซล Firebase (เรียกว่า "Gemini ใน Firebase")
- สำหรับ Codelab นี้ คุณไม่จำเป็นต้องใช้ Google Analytics ดังนั้นให้ปิดตัวเลือก Google Analytics
- คลิกสร้างโปรเจ็กต์ รอให้ระบบจัดสรรโปรเจ็กต์ แล้วคลิกดำเนินการต่อ
เชื่อมต่อแอปกับ Firebase
สร้างแอป iOS ในโปรเจ็กต์ Firebase ใหม่
ดาวน์โหลดไฟล์ GoogleService-Info.plist
ของโปรเจ็กต์จากคอนโซล Firebase แล้วลากไปยังรูทของโปรเจ็กต์ Xcode เรียกใช้โปรเจ็กต์อีกครั้งเพื่อให้แน่ใจว่าแอปได้รับการกำหนดค่าอย่างถูกต้องและไม่ขัดข้องเมื่อเปิดตัวอีกต่อไป หลังจากเข้าสู่ระบบแล้ว คุณควรเห็นหน้าจอว่างเปล่าเหมือนตัวอย่างด้านล่าง หากเข้าสู่ระบบไม่ได้ โปรดตรวจสอบว่าคุณได้เปิดใช้เมธอดการลงชื่อเข้าใช้ด้วยอีเมล/รหัสผ่านในคอนโซล Firebase ภายใต้การตรวจสอบสิทธิ์แล้ว
4 เขียนข้อมูลไปยัง Firestore
ในส่วนนี้ เราจะเขียนข้อมูลบางอย่างลงใน Firestore เพื่อให้เราสามารถแสดงข้อมูลใน UI ของแอปได้ คุณทำได้ด้วยตนเองผ่านคอนโซล Firebase แต่เราจะดำเนินการในแอปเองเพื่อแสดงการเขียน Firestore ขั้นพื้นฐาน
ออบเจ็กต์โมเดลหลักในแอปของเราคือร้านอาหาร ข้อมูล Firestore จะแบ่งออกเป็นเอกสาร คอลเล็กชัน และคอลเล็กชันย่อย เราจะจัดเก็บร้านอาหารแต่ละร้านเป็นเอกสารในคอลเล็กชันระดับบนสุดที่ชื่อ restaurants
หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับโมเดลข้อมูล Firestore โปรดอ่านเกี่ยวกับเอกสารและคอลเล็กชันในเอกสารประกอบ
ก่อนที่จะเพิ่มข้อมูลลงใน Firestore ได้ เราต้องรับการอ้างอิงไปยังคอลเล็กชันร้านอาหาร เพิ่มโค้ดต่อไปนี้ในลูป for ด้านในในเมธอด RestaurantsTableViewController.didTapPopulateButton(_:)
let collection = Firestore.firestore().collection("restaurants")
ตอนนี้เรามีข้อมูลอ้างอิงของคอลเล็กชันแล้ว เราจึงเขียนข้อมูลบางอย่างได้ เพิ่มโค้ดต่อไปนี้ต่อจากบรรทัดสุดท้ายของโค้ดที่เราเพิ่ม
let collection = Firestore.firestore().collection("restaurants")
// ====== ADD THIS ======
let restaurant = Restaurant(
name: name,
category: category,
city: city,
price: price,
ratingCount: 0,
averageRating: 0
)
collection.addDocument(data: restaurant.dictionary)
โค้ดด้านบนจะเพิ่มเอกสารใหม่ลงในคอลเล็กชันร้านอาหาร ข้อมูลเอกสารมาจากพจนานุกรมซึ่งเราได้รับจากโครงสร้างร้านอาหาร
เรามาถึงขั้นตอนสุดท้ายแล้ว ก่อนที่จะเขียนเอกสารลงใน Firestore ได้ เราต้องเปิดกฎความปลอดภัยของ Firestore และอธิบายว่าผู้ใช้รายใดควรมีสิทธิ์เขียนส่วนใดของฐานข้อมูล ตอนนี้เราจะอนุญาตให้เฉพาะผู้ใช้ที่ตรวจสอบสิทธิ์แล้วเท่านั้นที่อ่านและเขียนไปยังทั้งฐานข้อมูลได้ ซึ่งอาจเป็นข้อจำกัดที่มากเกินไปสำหรับแอปเวอร์ชันที่ใช้งานจริง แต่ในระหว่างกระบวนการสร้างแอป เราต้องการข้อจำกัดที่ยืดหยุ่นพอที่จะไม่ทำให้เกิดปัญหาการตรวจสอบสิทธิ์อยู่ตลอดเวลาขณะทดลอง ในช่วงท้ายของโค้ดแล็บนี้ เราจะพูดถึงวิธีเพิ่มความแข็งแกร่งให้กับกฎความปลอดภัยและจำกัดความเป็นไปได้ของการอ่านและการเขียนโดยไม่ตั้งใจ
ในแท็บกฎของคอนโซล Firebase ให้เพิ่มกฎต่อไปนี้ แล้วคลิกเผยแพร่
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /restaurants/{any}/ratings/{rating} { // Users can only write ratings with their user ID allow read; allow write: if request.auth != null && request.auth.uid == request.resource.data.userId; } match /restaurants/{any} { // Only authenticated users can read or write data allow read, write: if request.auth != null; } } }
เราจะพูดถึงกฎการรักษาความปลอดภัยอย่างละเอียดในภายหลัง แต่หากคุณรีบร้อน โปรดดูเอกสารประกอบเกี่ยวกับกฎการรักษาความปลอดภัย
เรียกใช้แอปและลงชื่อเข้าใช้ จากนั้นแตะปุ่ม "ป้อนข้อมูล" ที่ด้านซ้ายบน ซึ่งจะสร้างเอกสารร้านอาหารเป็นชุด แต่คุณจะยังไม่เห็นเอกสารนี้ในแอป
จากนั้นไปที่แท็บข้อมูล Firestore ในคอนโซล Firebase ตอนนี้คุณควรเห็นรายการใหม่ในคอลเล็กชันร้านอาหารแล้ว
ขอแสดงความยินดี คุณเพิ่งเขียนข้อมูลลงใน Firestore จากแอป iOS ในส่วนถัดไป คุณจะได้เรียนรู้วิธีดึงข้อมูลจาก Firestore และแสดงในแอป
5 แสดงข้อมูลจาก Firestore
ในส่วนนี้ คุณจะได้เรียนรู้วิธีดึงข้อมูลจาก Firestore และแสดงในแอป ขั้นตอนสำคัญ 2 อย่างคือการสร้างการค้นหาและการเพิ่มเครื่องมือฟังภาพรวม Listener นี้จะได้รับการแจ้งเตือนเกี่ยวกับข้อมูลที่มีอยู่ทั้งหมดที่ตรงกับการค้นหาและได้รับการอัปเดตแบบเรียลไทม์
ก่อนอื่น มาสร้างคำค้นหาที่จะแสดงรายการร้านอาหารเริ่มต้นที่ไม่มีการกรองกัน ดูการติดตั้งใช้งาน RestaurantsTableViewController.baseQuery()
return Firestore.firestore().collection("restaurants").limit(to: 50)
คำค้นหานี้จะดึงร้านอาหารได้สูงสุด 50 แห่งจากคอลเล็กชันระดับบนสุดที่ชื่อ "restaurants" ตอนนี้เรามีคำค้นหาแล้ว เราจึงต้องแนบเครื่องมือฟังการสแนปชอตเพื่อโหลดข้อมูลจาก Firestore ลงในแอป เพิ่มโค้ดต่อไปนี้ลงในเมธอด RestaurantsTableViewController.observeQuery()
ทันทีหลังจากเรียกใช้ stopObserving()
listener = query.addSnapshotListener { [unowned self] (snapshot, error) in
guard let snapshot = snapshot else {
print("Error fetching snapshot results: \(error!)")
return
}
let models = snapshot.documents.map { (document) -> Restaurant in
if let model = Restaurant(dictionary: document.data()) {
return model
} else {
// Don't use fatalError here in a real app.
fatalError("Unable to initialize type \(Restaurant.self) with dictionary \(document.data())")
}
}
self.restaurants = models
self.documents = snapshot.documents
if self.documents.count > 0 {
self.tableView.backgroundView = nil
} else {
self.tableView.backgroundView = self.backgroundView
}
self.tableView.reloadData()
}
โค้ดด้านบนจะดาวน์โหลดคอลเล็กชันจาก Firestore และจัดเก็บไว้ในอาร์เรย์ในเครื่อง addSnapshotListener(_:)
จะเพิ่ม Listener ของสแนปชอตลงในการค้นหาที่จะอัปเดต ViewController ทุกครั้งที่ข้อมูลมีการเปลี่ยนแปลงในเซิร์ฟเวอร์ เราจะได้รับการอัปเดตโดยอัตโนมัติและไม่ต้องพุชการเปลี่ยนแปลงด้วยตนเอง โปรดทราบว่าระบบจะเรียกใช้เครื่องมือฟังภาพรวมนี้ได้ทุกเมื่ออันเป็นผลมาจากการเปลี่ยนแปลงฝั่งเซิร์ฟเวอร์ ดังนั้นแอปของเราจึงต้องรองรับการเปลี่ยนแปลงได้
หลังจากแมปพจนานุกรมกับโครงสร้าง (ดู Restaurant.swift
) การแสดงข้อมูลก็เป็นเพียงการกำหนดพร็อพเพอร์ตี้ของมุมมอง 2-3 รายการ เพิ่มบรรทัดต่อไปนี้ลงใน RestaurantTableViewCell.populate(restaurant:)
ใน RestaurantsTableViewController.swift
nameLabel.text = restaurant.name
cityLabel.text = restaurant.city
categoryLabel.text = restaurant.category
starsView.rating = Int(restaurant.averageRating.rounded())
priceLabel.text = priceString(from: restaurant.price)
วิธีการป้อนข้อมูลนี้เรียกใช้จากเมธอด tableView(_:cellForRowAtIndexPath:)
ของแหล่งข้อมูลมุมมองตาราง ซึ่งจะดูแลการแมปคอลเล็กชันของประเภทค่าจากก่อนหน้าไปยังเซลล์มุมมองตารางแต่ละเซลล์
เรียกใช้แอปอีกครั้งและตรวจสอบว่าร้านอาหารที่เราเห็นก่อนหน้านี้ในคอนโซลปรากฏในโปรแกรมจำลองหรืออุปกรณ์แล้ว หากทำส่วนนี้สำเร็จ ตอนนี้แอปของคุณจะอ่านและเขียนข้อมูลด้วย Cloud Firestore ได้แล้ว
6 การจัดเรียงและการกรองข้อมูล
ปัจจุบันแอปของเราแสดงรายชื่อร้านอาหาร แต่ผู้ใช้ไม่สามารถกรองตามความต้องการได้ ในส่วนนี้ คุณจะได้ใช้การค้นหาขั้นสูงของ Firestore เพื่อเปิดใช้การกรอง
ต่อไปนี้คือตัวอย่างคําค้นหาอย่างง่ายเพื่อดึงร้านอาหารติ่มซำทั้งหมด
let filteredQuery = query.whereField("category", isEqualTo: "Dim Sum")
ตามชื่อของฟังก์ชัน whereField(_:isEqualTo:)
เมธอดจะทำให้การดาวน์โหลดคำค้นหาของเรามีเฉพาะสมาชิกของคอลเล็กชันที่มีช่องตรงตามข้อจำกัดที่เราตั้งไว้ ในกรณีนี้ ระบบจะดาวน์โหลดเฉพาะร้านอาหารที่ category
เป็น "Dim Sum"
ในแอปนี้ ผู้ใช้สามารถเชื่อมโยงตัวกรองหลายรายการเพื่อสร้างคำค้นหาที่เฉพาะเจาะจง เช่น "พิซซ่าในซานฟรานซิสโก" หรือ "อาหารทะเลในลอสแอนเจลิสที่จัดเรียงตามความนิยม"
เปิด RestaurantsTableViewController.swift
แล้วเพิ่มโค้ดบล็อกต่อไปนี้ตรงกลางของ query(withCategory:city:price:sortBy:)
if let category = category, !category.isEmpty {
filtered = filtered.whereField("category", isEqualTo: category)
}
if let city = city, !city.isEmpty {
filtered = filtered.whereField("city", isEqualTo: city)
}
if let price = price {
filtered = filtered.whereField("price", isEqualTo: price)
}
if let sortBy = sortBy, !sortBy.isEmpty {
filtered = filtered.order(by: sortBy)
}
ข้อมูลโค้ดด้านบนจะเพิ่มคําสั่ง whereField
และ order
หลายรายการเพื่อสร้างคําค้นหาแบบผสมรายการเดียวตามข้อมูลที่ผู้ใช้ป้อน ตอนนี้การค้นหาจะแสดงเฉพาะร้านอาหารที่ตรงกับความต้องการของผู้ใช้เท่านั้น
เรียกใช้โปรเจ็กต์และตรวจสอบว่าคุณกรองตามราคา เมือง และหมวดหมู่ได้ (ตรวจสอบว่าได้พิมพ์ชื่อหมวดหมู่และเมืองอย่างถูกต้อง) ขณะทดสอบ คุณอาจเห็นข้อผิดพลาดในบันทึกที่มีลักษณะดังนี้
Error fetching snapshot results: Error Domain=io.grpc Code=9 "The query requires an index. You can create it here: https://console.firebase.google.com/project/project-id/database/firestore/indexes?create_composite=..." UserInfo={NSLocalizedDescription=The query requires an index. You can create it here: https://console.firebase.google.com/project/project-id/database/firestore/indexes?create_composite=...}
เนื่องจาก Firestore ต้องใช้ดัชนีสำหรับการค้นหาแบบผสมส่วนใหญ่ การกำหนดให้ใช้ดัชนีในการค้นหาจะช่วยให้ Firestore ทำงานได้อย่างรวดเร็วเมื่อมีการปรับขนาด การเปิดลิงก์จากข้อความแสดงข้อผิดพลาดจะเปิด UI การสร้างดัชนีในคอนโซล Firebase โดยอัตโนมัติพร้อมกับพารามิเตอร์ที่ถูกต้อง ดูข้อมูลเพิ่มเติมเกี่ยวกับดัชนีใน Firestore ได้ที่เอกสารประกอบ
7 การเขียนข้อมูลในธุรกรรม
ในส่วนนี้ เราจะเพิ่มความสามารถให้ผู้ใช้ส่งรีวิวไปยังร้านอาหารได้ จนถึงตอนนี้ การเขียนทั้งหมดของเราเป็นแบบอะตอมมิกและค่อนข้างเรียบง่าย หากมีข้อผิดพลาดเกิดขึ้น เราอาจแจ้งให้ผู้ใช้ลองอีกครั้งหรือลองอีกครั้งโดยอัตโนมัติ
หากต้องการเพิ่มคะแนนให้กับร้านอาหาร เราต้องประสานงานการอ่านและการเขียนหลายครั้ง โดยคุณต้องส่งรีวิวก่อน จากนั้นจึงอัปเดตจำนวนการให้คะแนนและคะแนนเฉลี่ยของร้านอาหาร หากการดำเนินการอย่างใดอย่างหนึ่งล้มเหลว แต่การดำเนินการอีกอย่างหนึ่งสำเร็จ เราจะอยู่ในสถานะที่ไม่สอดคล้องกัน ซึ่งข้อมูลในส่วนหนึ่งของฐานข้อมูลไม่ตรงกับข้อมูลในอีกส่วนหนึ่ง
โชคดีที่ Firestore มีฟังก์ชันการทำธุรกรรมที่ช่วยให้เราอ่านและเขียนหลายครั้งในการดำเนินการแบบอะตอมเดียวได้ ซึ่งจะช่วยให้ข้อมูลของเรายังคงสอดคล้องกัน
เพิ่มโค้ดต่อไปนี้ใต้การประกาศ let ทั้งหมดใน RestaurantDetailViewController.reviewController(_:didSubmitFormWithReview:)
let firestore = Firestore.firestore()
firestore.runTransaction({ (transaction, errorPointer) -> Any? in
// Read data from Firestore inside the transaction, so we don't accidentally
// update using stale client data. Error if we're unable to read here.
let restaurantSnapshot: DocumentSnapshot
do {
try restaurantSnapshot = transaction.getDocument(reference)
} catch let error as NSError {
errorPointer?.pointee = error
return nil
}
// Error if the restaurant data in Firestore has somehow changed or is malformed.
guard let data = restaurantSnapshot.data(),
let restaurant = Restaurant(dictionary: data) else {
let error = NSError(domain: "FireEatsErrorDomain", code: 0, userInfo: [
NSLocalizedDescriptionKey: "Unable to write to restaurant at Firestore path: \(reference.path)"
])
errorPointer?.pointee = error
return nil
}
// Update the restaurant's rating and rating count and post the new review at the
// same time.
let newAverage = (Float(restaurant.ratingCount) * restaurant.averageRating + Float(review.rating))
/ Float(restaurant.ratingCount + 1)
transaction.setData(review.dictionary, forDocument: newReviewReference)
transaction.updateData([
"numRatings": restaurant.ratingCount + 1,
"avgRating": newAverage
], forDocument: reference)
return nil
}) { (object, error) in
if let error = error {
print(error)
} else {
// Pop the review controller on success
if self.navigationController?.topViewController?.isKind(of: NewReviewViewController.self) ?? false {
self.navigationController?.popViewController(animated: true)
}
}
}
ภายในบล็อกการอัปเดต การดำเนินการทั้งหมดที่เราทำโดยใช้ออบเจ็กต์ธุรกรรมจะถือเป็นการอัปเดตแบบอะตอมเดียวโดย Firestore หากอัปเดตในเซิร์ฟเวอร์ไม่สำเร็จ Firestore จะลองอีกครั้งโดยอัตโนมัติ 2-3 ครั้ง ซึ่งหมายความว่าเงื่อนไขข้อผิดพลาดของเรามักจะเป็นข้อผิดพลาดเดียวที่เกิดขึ้นซ้ำๆ เช่น หากอุปกรณ์ออฟไลน์โดยสมบูรณ์ หรือผู้ใช้ไม่มีสิทธิ์เขียนไปยังเส้นทางที่พยายามเขียน
8 กฎความปลอดภัย
ผู้ใช้แอปของเราไม่ควรอ่านและเขียนข้อมูลทุกชิ้นในฐานข้อมูลของเราได้ เช่น ทุกคนควรดูคะแนนของร้านอาหารได้ แต่ควรอนุญาตให้เฉพาะผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์แล้วเท่านั้นที่โพสต์คะแนนได้ การเขียนโค้ดที่ดีในไคลเอ็นต์ยังไม่เพียงพอ เราต้องระบุโมเดลความปลอดภัยของข้อมูลในแบ็กเอนด์เพื่อให้ปลอดภัยอย่างสมบูรณ์ ในส่วนนี้ เราจะมาดูวิธีใช้กฎความปลอดภัยของ Firebase เพื่อปกป้องข้อมูล
ก่อนอื่น มาดูรายละเอียดกฎความปลอดภัยที่เราเขียนไว้ตอนเริ่ม Codelab กัน เปิดคอนโซล Firebase แล้วไปที่ฐานข้อมูล > กฎในแท็บ Firestore
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /restaurants/{any}/ratings/{rating} {
// Users can only write ratings with their user ID
allow read;
allow write: if request.auth != null
&& request.auth.uid == request.resource.data.userId;
}
match /restaurants/{any} {
// Only authenticated users can read or write data
allow read, write: if request.auth != null;
}
}
}
ตัวแปร request
ในกฎเป็นตัวแปรส่วนกลางที่ใช้ได้ในทุกกฎ และเงื่อนไขที่เราเพิ่มเข้าไปจะช่วยให้มั่นใจได้ว่าคำขอจะได้รับการตรวจสอบสิทธิ์ก่อนที่จะอนุญาตให้ผู้ใช้ทำสิ่งใดก็ตาม ซึ่งจะช่วยป้องกันไม่ให้ผู้ใช้ที่ไม่ได้รับการตรวจสอบสิทธิ์ใช้ Firestore API เพื่อทำการเปลี่ยนแปลงข้อมูลโดยไม่ได้รับอนุญาต นี่เป็นจุดเริ่มต้นที่ดี แต่เราสามารถใช้กฎ Firestore เพื่อทำสิ่งต่างๆ ที่มีประสิทธิภาพมากขึ้นได้
เราต้องการจำกัดการเขียนรีวิวเพื่อให้รหัสผู้ใช้ของรีวิวต้องตรงกับรหัสของผู้ใช้ที่ผ่านการตรวจสอบสิทธิ์ ซึ่งช่วยให้มั่นใจได้ว่าผู้ใช้จะแอบอ้างเป็นบุคคลอื่นและเขียนรีวิวที่เป็นการฉ้อโกงไม่ได้
คำสั่งจับคู่แรกจะจับคู่คอลเล็กชันย่อยชื่อ ratings
ของเอกสารใดก็ตามที่อยู่ในคอลเล็กชัน restaurants
จากนั้นallow write
เงื่อนไขจะป้องกันไม่ให้ส่งรีวิวหากรหัสผู้ใช้ของรีวิวไม่ตรงกับรหัสของผู้ใช้ คำสั่งจับคู่ที่ 2 อนุญาตให้ผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์อ่านและเขียนร้านอาหารลงในฐานข้อมูล
ซึ่งใช้ได้ดีกับรีวิวของเรา เนื่องจากเราได้ใช้กฎความปลอดภัยเพื่อระบุการรับประกันโดยนัยที่เราเขียนไว้ในแอปก่อนหน้านี้อย่างชัดเจน นั่นคือผู้ใช้จะเขียนได้เฉพาะรีวิวของตนเอง หากเราเพิ่มฟังก์ชันแก้ไขหรือลบรีวิว ชุดกฎเดียวกันนี้จะป้องกันไม่ให้ผู้ใช้แก้ไขหรือลบรีวิวของผู้ใช้รายอื่นด้วย แต่คุณยังใช้กฎ Firestore ในลักษณะที่ละเอียดยิ่งขึ้นเพื่อจำกัดการเขียนในแต่ละช่องภายในเอกสารแทนที่จะเป็นทั้งเอกสารได้ด้วย เราสามารถใช้ข้อมูลนี้เพื่ออนุญาตให้ผู้ใช้อัปเดตเฉพาะคะแนน คะแนนเฉลี่ย และจำนวนคะแนนของร้านอาหารได้ ซึ่งจะช่วยลดโอกาสที่ผู้ใช้ที่เป็นอันตรายจะแก้ไขชื่อหรือตำแหน่งของร้านอาหาร
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /restaurants/{restaurant} {
match /ratings/{rating} {
allow read: if request.auth != null;
allow write: if request.auth != null
&& request.auth.uid == request.resource.data.userId;
}
allow read: if request.auth != null;
allow create: if request.auth != null;
allow update: if request.auth != null
&& request.resource.data.name == resource.data.name
&& request.resource.data.city == resource.data.city
&& request.resource.data.price == resource.data.price
&& request.resource.data.category == resource.data.category;
}
}
}
ในที่นี้ เราได้แยกสิทธิ์เขียนออกเป็นสร้างและอัปเดตเพื่อให้ระบุการดำเนินการที่ควรได้รับอนุญาตได้ชัดเจนยิ่งขึ้น ผู้ใช้ทุกคนเขียนร้านอาหารลงในฐานข้อมูลได้ โดยยังคงฟังก์ชันการทำงานของปุ่มป้อนข้อมูลที่เราสร้างขึ้นเมื่อเริ่ม Codelab แต่เมื่อเขียนร้านอาหารแล้ว จะเปลี่ยนชื่อ สถานที่ ราคา และหมวดหมู่ของร้านอาหารไม่ได้ กล่าวอย่างเจาะจงคือ กฎข้อสุดท้ายกำหนดให้การดำเนินการอัปเดตร้านอาหารต้องคงชื่อ เมือง ราคา และหมวดหมู่ของฟิลด์ที่มีอยู่แล้วในฐานข้อมูลไว้เหมือนเดิม
ดูข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่ดำเนินการกับกฎความปลอดภัยได้ที่เอกสารประกอบ
9 บทสรุป
ในโค้ดแล็บนี้ คุณได้เรียนรู้วิธีอ่านและเขียนข้อมูลพื้นฐานและขั้นสูงด้วย Firestore รวมถึงวิธีรักษาความปลอดภัยในการเข้าถึงข้อมูลด้วยกฎการรักษาความปลอดภัย คุณดูโซลูชันทั้งหมดได้ในcodelab-complete
Branch
ดูข้อมูลเพิ่มเติมเกี่ยวกับ Firestore ได้ที่แหล่งข้อมูลต่อไปนี้