1. ภาพรวม
เป้าหมาย
ในโค้ดแล็บนี้ คุณจะได้สร้างแอปแนะนำร้านอาหารที่รองรับ Firestore บน iOS ใน Swift คุณจะได้เรียนรู้วิธีต่อไปนี้
- อ่านและเขียนข้อมูลไปยัง Firestore จากแอป iOS
- ติดตามการเปลี่ยนแปลงข้อมูล Firestore แบบเรียลไทม์
- ใช้การตรวจสอบสิทธิ์ Firebase และกฎการรักษาความปลอดภัยเพื่อรักษาความปลอดภัยของข้อมูล Firestore
- เขียนการค้นหา Firestore ที่ซับซ้อน
ข้อกำหนดเบื้องต้น
ก่อนเริ่มใช้งาน Codelab นี้ โปรดตรวจสอบว่าคุณได้ติดตั้งสิ่งต่อไปนี้แล้ว
- Xcode เวอร์ชัน 14.0 (หรือสูงกว่า)
- CocoaPods 1.12.0 (หรือสูงกว่า)
2. สร้างโปรเจ็กต์คอนโซล Firebase
เพิ่ม Firebase ลงในโปรเจ็กต์
- ไปที่คอนโซล Firebase
- เลือกสร้างโปรเจ็กต์ใหม่ แล้วตั้งชื่อโปรเจ็กต์เป็น "Firestore iOS Codelab"
3. รับโปรเจ็กต์ตัวอย่าง
ดาวน์โหลดรหัส
เริ่มต้นด้วยการโคลนโปรเจ็กต์ตัวอย่างและเรียกใช้ pod update
ในไดเรกทอรีโปรเจ็กต์
git clone https://github.com/firebase/friendlyeats-ios cd friendlyeats-ios pod update
เปิด FriendlyEats.xcworkspace
ใน Xcode แล้วเรียกใช้ (Cmd+R) แอปควรคอมไพล์อย่างถูกต้องและขัดข้องทันทีที่เปิด เนื่องจากไม่มีไฟล์ GoogleService-Info.plist
เราจะแก้ไขในขั้นตอนถัดไป
ตั้งค่า Firebase
ทำตามเอกสารประกอบเพื่อสร้างโปรเจ็กต์ Firestore ใหม่ เมื่อสร้างโปรเจ็กต์แล้ว ให้ดาวน์โหลดไฟล์ 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)
โค้ดด้านบนจะเพิ่มเอกสารใหม่ลงในคอลเล็กชันร้านอาหาร ข้อมูลเอกสารมาจากพจนานุกรมที่เราได้รับจากโครงสร้าง Restaurant
เราเกือบจะเสร็จแล้ว ก่อนที่จะเขียนเอกสารลงใน 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" เมื่อเรามีคำถามแล้ว เราจะต้องแนบ Listener สแนปชอตเพื่อโหลดข้อมูลจาก 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 ของสแนปชอตลงในคําค้นหาที่จะอัปเดตตัวควบคุมมุมมองทุกครั้งที่มีการเปลี่ยนแปลงข้อมูลในเซิร์ฟเวอร์ เราจะได้รับการอัปเดตโดยอัตโนมัติและไม่ต้องพุชการเปลี่ยนแปลงด้วยตนเอง โปรดทราบว่าระบบอาจเรียกใช้เครื่องมือรับข้อมูลภาพนิ่งนี้ได้ทุกเมื่อเนื่องจากการเปลี่ยนแปลงฝั่งเซิร์ฟเวอร์ ดังนั้นแอปของเราจึงต้องจัดการการเปลี่ยนแปลงได้
หลังจากแมปพจนานุกรมกับโครงสร้าง (ดู 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)
ระบบเรียกใช้เมธอด "populate" นี้จากเมธอด 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 เพื่อปกป้องข้อมูลของเรา
ก่อนอื่น เรามาเจาะลึกกฎความปลอดภัยที่เราเขียนไว้ตอนเริ่มต้นโค้ดแล็บกัน เปิดคอนโซล 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;
}
}
}
ในส่วนนี้ เราได้แยกสิทธิ์การเขียนออกเป็น "สร้าง" และ "อัปเดต" เพื่อให้ระบุการดำเนินการที่ควรได้รับอนุญาตได้ชัดเจนยิ่งขึ้น ผู้ใช้ทุกคนสามารถเขียนร้านอาหารลงในฐานข้อมูลได้ ซึ่งจะยังคงฟังก์ชันการทำงานของปุ่มป้อนข้อมูลที่เราสร้างขึ้นไว้ตั้งแต่ต้นโค้ดแล็บ แต่เมื่อเขียนร้านอาหารแล้ว ผู้ใช้จะเปลี่ยนชื่อ สถานที่ตั้ง ราคา และหมวดหมู่ของร้านอาหารไม่ได้ กล่าวโดยละเอียดคือ กฎสุดท้ายกำหนดให้การดำเนินการอัปเดตร้านอาหารต้องคงชื่อ เมือง ราคา และหมวดหมู่เดิมของช่องที่มีอยู่แล้วในฐานข้อมูล
ดูข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่คุณทํากับกฎความปลอดภัยได้ได้ที่เอกสารประกอบ
9. บทสรุป
ในโค้ดแล็บนี้ คุณได้เรียนรู้วิธีอ่านและเขียนขั้นพื้นฐานและขั้นสูงด้วย Firestore รวมถึงวิธีรักษาความปลอดภัยในการเข้าถึงข้อมูลด้วยกฎการรักษาความปลอดภัย ดูโซลูชันทั้งหมดได้ใน codelab-complete
branch
ดูข้อมูลเพิ่มเติมเกี่ยวกับ Firestore ได้ที่แหล่งข้อมูลต่อไปนี้