1. সংক্ষিপ্ত বিবরণ
লক্ষ্য
এই কোডল্যাবে আপনি Swift-এ iOS-এ একটি Firestore-সমর্থিত রেস্তোরাঁ সুপারিশ অ্যাপ তৈরি করবেন। আপনি শিখবেন কিভাবে:
- iOS অ্যাপ থেকে Firestore-এ ডেটা পড়ুন এবং লিখুন
- রিয়েলটাইমে ফায়ারস্টোর ডেটার পরিবর্তনগুলি শুনুন
- ফায়ারস্টোর ডেটা সুরক্ষিত করতে ফায়ারবেস প্রমাণীকরণ এবং সুরক্ষা নিয়ম ব্যবহার করুন
- জটিল ফায়ারস্টোর কোয়েরি লিখুন
পূর্বশর্ত
এই কোডল্যাবটি শুরু করার আগে নিশ্চিত করুন যে আপনি ইনস্টল করেছেন:
- এক্সকোড সংস্করণ ১৪.০ (বা উচ্চতর)
- কোকোপডস ১.১২.০ (বা উচ্চতর)
2. নমুনা প্রকল্পটি পান
কোডটি ডাউনলোড করুন
নমুনা প্রকল্পটি ক্লোন করে এবং প্রকল্প ডিরেক্টরিতে pod update চালানোর মাধ্যমে শুরু করুন:
git clone https://github.com/firebase/friendlyeats-ios cd friendlyeats-ios pod update
Xcode-এ FriendlyEats.xcworkspace খুলুন এবং এটি চালান (Cmd+R)। অ্যাপটি সঠিকভাবে কম্পাইল করা উচিত এবং লঞ্চের সাথে সাথেই ক্র্যাশ হয়ে যাবে, কারণ এতে একটি GoogleService-Info.plist ফাইল নেই। আমরা পরবর্তী ধাপে এটি সংশোধন করব।
৩. ফায়ারবেস সেট আপ করুন
একটি ফায়ারবেস প্রকল্প তৈরি করুন
- আপনার গুগল অ্যাকাউন্ট ব্যবহার করে ফায়ারবেস কনসোলে সাইন ইন করুন।
- একটি নতুন প্রকল্প তৈরি করতে বোতামটি ক্লিক করুন, এবং তারপর একটি প্রকল্পের নাম লিখুন (উদাহরণস্বরূপ,
FriendlyEats)। - চালিয়ে যান ক্লিক করুন।
- যদি অনুরোধ করা হয়, তাহলে Firebase শর্তাবলী পর্যালোচনা করুন এবং গ্রহণ করুন, এবং তারপর Continue এ ক্লিক করুন।
- (ঐচ্ছিক) Firebase কনসোলে ("Gemini in Firebase" নামে পরিচিত) AI সহায়তা সক্ষম করুন।
- এই কোডল্যাবের জন্য, আপনার গুগল অ্যানালিটিক্সের প্রয়োজন নেই , তাই গুগল অ্যানালিটিক্স বিকল্পটি টগল করে বন্ধ করে দিন ।
- Create project এ ক্লিক করুন, আপনার province করার জন্য অপেক্ষা করুন, এবং তারপর Continue এ ক্লিক করুন।
আপনার অ্যাপটি Firebase-এর সাথে সংযুক্ত করুন
আপনার নতুন Firebase প্রকল্পে একটি iOS অ্যাপ তৈরি করুন।
Firebase কনসোল থেকে আপনার প্রোজেক্টের GoogleService-Info.plist ফাইলটি ডাউনলোড করুন এবং Xcode প্রোজেক্টের রুটে টেনে আনুন। অ্যাপটি সঠিকভাবে কনফিগার হয়েছে কিনা এবং লঞ্চের সময় আর ক্র্যাশ হচ্ছে না তা নিশ্চিত করতে প্রোজেক্টটি আবার চালান। লগ ইন করার পরে, আপনি নীচের উদাহরণের মতো একটি ফাঁকা স্ক্রিন দেখতে পাবেন। যদি আপনি লগ ইন করতে না পারেন, তাহলে নিশ্চিত করুন যে আপনি Firebase কনসোলে Authentication এর অধীনে Email/Password সাইন-ইন পদ্ধতি সক্ষম করেছেন।

৪. ফায়ারস্টোরে ডেটা লিখুন
এই বিভাগে আমরা Firestore-এ কিছু ডেটা লিখব যাতে আমরা অ্যাপ UI পূরণ করতে পারি। এটি Firebase কনসোলের মাধ্যমে ম্যানুয়ালি করা যেতে পারে, তবে আমরা একটি মৌলিক Firestore লেখা প্রদর্শনের জন্য অ্যাপেই এটি করব।
আমাদের অ্যাপের মূল মডেল অবজেক্ট হল একটি রেস্তোরাঁ। ফায়ারস্টোর ডেটা ডকুমেন্ট, সংগ্রহ এবং উপ-সংগ্রহে বিভক্ত। আমরা প্রতিটি রেস্তোরাঁকে restaurants নামক একটি শীর্ষ-স্তরের সংগ্রহে একটি নথি হিসাবে সংরক্ষণ করব। আপনি যদি ফায়ারস্টোর ডেটা মডেল সম্পর্কে আরও জানতে চান, তাহলে ডকুমেন্টেশনে ডকুমেন্ট এবং সংগ্রহ সম্পর্কে পড়ুন।
Firestore-এ ডেটা যোগ করার আগে, আমাদের রেস্তোরাঁ সংগ্রহের একটি রেফারেন্স পেতে হবে। RestaurantsTableViewController.didTapPopulateButton(_:) পদ্ধতিতে ভিতরের for লুপে নিম্নলিখিতটি যোগ করুন।
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)
উপরের কোডটি রেস্তোরাঁ সংগ্রহে একটি নতুন ডকুমেন্ট যোগ করেছে। ডকুমেন্টের তথ্য একটি অভিধান থেকে এসেছে, যা আমরা একটি রেস্তোরাঁ কাঠামো থেকে পাই।
আমরা প্রায় সেখানে পৌঁছে গেছি - ফায়ারস্টোরে ডকুমেন্ট লেখার আগে আমাদের ফায়ারস্টোরের নিরাপত্তা নিয়ম খুলতে হবে এবং আমাদের ডাটাবেসের কোন অংশ কোন ব্যবহারকারীদের দ্বারা লেখা যায় তা বর্ণনা করতে হবে। আপাতত, আমরা কেবলমাত্র প্রমাণিত ব্যবহারকারীদেরই সম্পূর্ণ ডাটাবেস পড়তে এবং লিখতে দেব। এটি একটি প্রোডাকশন অ্যাপের জন্য একটু বেশিই অনুমতিমূলক, তবে অ্যাপ তৈরির প্রক্রিয়া চলাকালীন আমরা যথেষ্ট শিথিল কিছু চাই যাতে পরীক্ষা-নিরীক্ষার সময় আমাদের ক্রমাগত প্রমাণীকরণের সমস্যা না হয়। এই কোডল্যাবের শেষে আমরা আপনার নিরাপত্তা নিয়মগুলিকে কীভাবে কঠোর করা যায় এবং অনিচ্ছাকৃত পড়া এবং লেখার সম্ভাবনা সীমিত করা যায় সে সম্পর্কে কথা বলব।
Firebase কনসোলের Rules ট্যাবে নিম্নলিখিত নিয়মগুলি যোগ করুন এবং তারপর Publish এ ক্লিক করুন।
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;
}
}
}
আমরা পরে নিরাপত্তা নিয়ম সম্পর্কে বিস্তারিত আলোচনা করব, তবে যদি আপনার তাড়াহুড়ো থাকে, তাহলে নিরাপত্তা নিয়মের ডকুমেন্টেশনটি একবার দেখে নিন।
অ্যাপটি চালান এবং সাইন ইন করুন। তারপর উপরের বাম দিকে " Populate " বোতামটি আলতো চাপুন, যা রেস্তোরাঁর নথির একটি ব্যাচ তৈরি করবে, যদিও আপনি এখনও অ্যাপটিতে এটি দেখতে পাবেন না।
এরপর, Firebase কনসোলে Firestore ডেটা ট্যাবে যান। এখন আপনি রেস্তোরাঁ সংগ্রহে নতুন এন্ট্রি দেখতে পাবেন:

অভিনন্দন, আপনি একটি iOS অ্যাপ থেকে Firestore-এ ডেটা লিখেছেন! পরবর্তী বিভাগে আপনি শিখবেন কিভাবে Firestore থেকে ডেটা পুনরুদ্ধার করতে হয় এবং অ্যাপে প্রদর্শন করতে হয়।
৫. ফায়ারস্টোর থেকে ডেটা প্রদর্শন করুন
এই বিভাগে আপনি শিখবেন কিভাবে ফায়ারস্টোর থেকে ডেটা পুনরুদ্ধার করতে হয় এবং অ্যাপে প্রদর্শন করতে হয়। দুটি গুরুত্বপূর্ণ ধাপ হল একটি কোয়েরি তৈরি করা এবং একটি স্ন্যাপশট লিসেনার যোগ করা। এই লিসেনারকে কোয়েরির সাথে মেলে এমন সমস্ত বিদ্যমান ডেটা সম্পর্কে অবহিত করা হবে এবং রিয়েল টাইমে আপডেটগুলি পাবেন।
প্রথমে, আসুন এমন একটি কোয়েরি তৈরি করি যা রেস্তোরাঁর ডিফল্ট, ফিল্টারবিহীন তালিকা পরিবেশন করবে। RestaurantsTableViewController.baseQuery() এর বাস্তবায়নটি একবার দেখে নিন:
return Firestore.firestore().collection("restaurants").limit(to: 50)
এই কোয়েরিটি "restaurants" নামক শীর্ষ-স্তরের সংগ্রহের ৫০টি পর্যন্ত রেস্তোরাঁ পুনরুদ্ধার করে। এখন আমাদের কাছে একটি কোয়েরি আছে, আমাদের অ্যাপে Firestore থেকে ডেটা লোড করার জন্য একটি স্ন্যাপশট লিসেনার সংযুক্ত করতে হবে। stopObserving() এ কল করার ঠিক পরে RestaurantsTableViewController.observeQuery() পদ্ধতিতে নিম্নলিখিত কোডটি যুক্ত করুন।
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(_:) কলটি কোয়েরিতে একটি স্ন্যাপশট লিসেনার যোগ করে যা সার্ভারে ডেটা পরিবর্তনের সময় প্রতিবার ভিউ কন্ট্রোলার আপডেট করবে। আমরা স্বয়ংক্রিয়ভাবে আপডেট পাই এবং ম্যানুয়ালি পরিবর্তনগুলি পুশ করতে হয় না। মনে রাখবেন, সার্ভার-সাইড পরিবর্তনের ফলে যে কোনও সময় এই স্ন্যাপশট লিসেনারটি আহ্বান করা যেতে পারে তাই আমাদের অ্যাপটি পরিবর্তনগুলি পরিচালনা করতে পারে তা গুরুত্বপূর্ণ।
আমাদের অভিধানগুলিকে structs-এ ম্যাপ করার পর ( Restaurant.swift দেখুন), ডেটা প্রদর্শন করা কেবল কয়েকটি ভিউ প্রপার্টি বরাদ্দ করার ব্যাপার। RestaurantsTableViewController.swift এ RestaurantTableViewCell.populate(restaurant:) তে নিম্নলিখিত লাইনগুলি যোগ করুন।
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:) পদ্ধতি থেকে ডাকা হয়, যা পূর্ববর্তী মানের ধরণগুলির সংগ্রহকে পৃথক টেবিল ভিউ কোষে ম্যাপ করার যত্ন নেয়।
অ্যাপটি আবার চালান এবং যাচাই করুন যে কনসোলে আমরা আগে যে রেস্তোরাঁগুলি দেখেছিলাম সেগুলি এখন সিমুলেটর বা ডিভাইসে দৃশ্যমান। আপনি যদি এই বিভাগটি সফলভাবে সম্পন্ন করেন তবে আপনার অ্যাপটি এখন ক্লাউড ফায়ারস্টোরের সাহায্যে ডেটা পড়ছে এবং লিখছে!

৬. ডেটা বাছাই এবং ফিল্টারিং
বর্তমানে আমাদের অ্যাপে রেস্তোরাঁর তালিকা দেখানো হচ্ছে, কিন্তু ব্যবহারকারীর চাহিদা অনুযায়ী ফিল্টার করার কোনও উপায় নেই। এই বিভাগে আপনি ফিল্টারিং সক্ষম করতে ফায়ারস্টোরের উন্নত কোয়েরি ব্যবহার করবেন।
সকল ডিম সাম রেস্তোরাঁ আনার জন্য একটি সহজ প্রশ্নের উদাহরণ এখানে দেওয়া হল:
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=...}
এর কারণ হল, বেশিরভাগ যৌগিক প্রশ্নের জন্য ফায়ারস্টোরের ইনডেক্সের প্রয়োজন হয়। কোয়েরিতে ইনডেক্সের প্রয়োজন হলে ফায়ারস্টোর দ্রুত স্কেলে চলে। ত্রুটি বার্তা থেকে লিঙ্কটি খোলার ফলে ফায়ারবেস কনসোলে ইনডেক্স তৈরির UI স্বয়ংক্রিয়ভাবে খুলবে এবং সঠিক প্যারামিটারগুলি পূরণ করা হবে। ফায়ারস্টোরে ইনডেক্স সম্পর্কে আরও জানতে, ডকুমেন্টেশন দেখুন ।
৭. লেনদেনে তথ্য লেখা
এই বিভাগে, আমরা ব্যবহারকারীদের রেস্তোরাঁয় পর্যালোচনা জমা দেওয়ার ক্ষমতা যোগ করব। এখনও পর্যন্ত, আমাদের সমস্ত লেখাই অসম্পূর্ণ এবং তুলনামূলকভাবে সহজ ছিল। যদি কোনওটিতে ত্রুটি থাকে, তাহলে আমরা সম্ভবত ব্যবহারকারীকে পুনরায় চেষ্টা করার জন্য অনুরোধ করব অথবা স্বয়ংক্রিয়ভাবে পুনরায় চেষ্টা করব।
একটি রেস্তোরাঁয় রেটিং যোগ করার জন্য আমাদের একাধিক পঠন এবং লেখার সমন্বয় করতে হবে। প্রথমে পর্যালোচনাটি জমা দিতে হবে, এবং তারপরে রেস্তোরাঁর রেটিং গণনা এবং গড় রেটিং আপডেট করতে হবে। যদি এর মধ্যে একটি ব্যর্থ হয় কিন্তু অন্যটি না হয়, তাহলে আমরা একটি অসামঞ্জস্যপূর্ণ অবস্থায় পড়ে যাই যেখানে আমাদের ডাটাবেসের এক অংশের ডেটা অন্য অংশের ডেটার সাথে মেলে না।
সৌভাগ্যবশত, ফায়ারস্টোর লেনদেন কার্যকারিতা প্রদান করে যা আমাদেরকে একটি একক পারমাণবিক অপারেশনে একাধিক পঠন এবং লেখার সুযোগ দেয়, যা নিশ্চিত করে যে আমাদের ডেটা সামঞ্জস্যপূর্ণ থাকে।
RestaurantDetailViewController.reviewController(_:didSubmitFormWithReview:) এর সকল let ঘোষণার নিচে নিম্নলিখিত কোডটি যোগ করুন।
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)
}
}
}
আপডেট ব্লকের ভেতরে, লেনদেন অবজেক্ট ব্যবহার করে আমরা যে সমস্ত ক্রিয়াকলাপ করি তা ফায়ারস্টোর দ্বারা একটি একক পারমাণবিক আপডেট হিসাবে বিবেচিত হবে। যদি সার্ভারে আপডেটটি ব্যর্থ হয়, তাহলে ফায়ারস্টোর স্বয়ংক্রিয়ভাবে কয়েকবার পুনরায় চেষ্টা করবে। এর অর্থ হল আমাদের ত্রুটির অবস্থা সম্ভবত বারবার ঘটছে এমন একটি ত্রুটি, উদাহরণস্বরূপ যদি ডিভাইসটি সম্পূর্ণ অফলাইন থাকে বা ব্যবহারকারী যে পথে লেখার চেষ্টা করছেন সেখানে লেখার জন্য অনুমোদিত না হন।
৮. নিরাপত্তা বিধি
আমাদের অ্যাপের ব্যবহারকারীরা আমাদের ডাটাবেসের প্রতিটি তথ্য পড়তে এবং লিখতে সক্ষম হবেন না। উদাহরণস্বরূপ, প্রত্যেকেরই একটি রেস্তোরাঁর রেটিং দেখতে পাওয়া উচিত, তবে কেবলমাত্র একজন অনুমোদিত ব্যবহারকারীকেই রেটিং পোস্ট করার অনুমতি দেওয়া উচিত। ক্লায়েন্টে ভালো কোড লেখা যথেষ্ট নয়, সম্পূর্ণ নিরাপদ থাকার জন্য আমাদের ব্যাকএন্ডে আমাদের ডেটা সুরক্ষা মডেল নির্দিষ্ট করতে হবে। এই বিভাগে আমরা শিখব কিভাবে আমাদের ডেটা সুরক্ষিত করার জন্য Firebase সুরক্ষা নিয়ম ব্যবহার করতে হয়।
প্রথমে, কোডল্যাবের শুরুতে আমরা যে নিরাপত্তা নিয়মগুলি লিখেছিলাম সেগুলি আরও গভীরভাবে দেখে নেওয়া যাক। Firebase কনসোলটি খুলুন এবং Firestore ট্যাবে Database > Rules এ নেভিগেট করুন।
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 নিয়ম ব্যবহার করতে পারি।
আমরা পর্যালোচনা লেখা সীমিত করতে চাই যাতে পর্যালোচনার ব্যবহারকারীর আইডি অবশ্যই প্রমাণিত ব্যবহারকারীর আইডির সাথে মিলে যায়। এটি নিশ্চিত করে যে ব্যবহারকারীরা একে অপরের ছদ্মবেশ ধারণ করতে এবং প্রতারণামূলক পর্যালোচনা ছেড়ে যেতে না পারে।
প্রথম ম্যাচ স্টেটমেন্টটি restaurants সংগ্রহের যেকোনো ডকুমেন্টের সাব-কালেকশন নামক ratings এর সাথে মিলে যায়। যদি পর্যালোচনার ব্যবহারকারী আইডি ব্যবহারকারীর আইডির সাথে না মেলে, তাহলে ' allow write শর্তসাপেক্ষে কোনও পর্যালোচনা জমা দেওয়া যাবে না। দ্বিতীয় ম্যাচ স্টেটমেন্টটি যেকোনো প্রমাণীকৃত ব্যবহারকারীকে ডাটাবেসে রেস্তোরাঁ পড়তে এবং লিখতে দেয়।
এটি আমাদের পর্যালোচনার জন্য সত্যিই ভালো কাজ করে, কারণ আমরা নিরাপত্তা নিয়ম ব্যবহার করে আমাদের অ্যাপে আগে যে অন্তর্নিহিত গ্যারান্টি লিখেছিলাম তা স্পষ্টভাবে জানিয়েছি - ব্যবহারকারীরা কেবল তাদের নিজস্ব পর্যালোচনা লিখতে পারবেন। যদি আমরা পর্যালোচনার জন্য একটি সম্পাদনা বা মুছে ফেলার ফাংশন যোগ করি, তাহলে ঠিক এই একই নিয়ম ব্যবহারকারীদের অন্য ব্যবহারকারীদের পর্যালোচনা পরিবর্তন বা মুছে ফেলা থেকেও বিরত রাখবে। তবে ফায়ারস্টোর নিয়মগুলি সম্পূর্ণ নথির পরিবর্তে নথির মধ্যে পৃথক ক্ষেত্রে লেখা সীমিত করার জন্য আরও সূক্ষ্মভাবে ব্যবহার করা যেতে পারে। আমরা এটি ব্যবহার করে ব্যবহারকারীদের শুধুমাত্র রেটিং, গড় রেটিং এবং রেটিং সংখ্যা আপডেট করার অনুমতি দিতে পারি, যার ফলে কোনও দূষিত ব্যবহারকারী কোনও রেস্তোরাঁর নাম বা অবস্থান পরিবর্তন করার সম্ভাবনা দূর হয়।
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;
}
}
}
এখানে আমরা আমাদের লেখার অনুমতিকে create এবং update এ বিভক্ত করেছি যাতে কোন কোন অপারেশনের অনুমতি দেওয়া উচিত সে সম্পর্কে আমরা আরও সুনির্দিষ্টভাবে বলতে পারি। কোডল্যাবের শুরুতে তৈরি করা পপুলেট বোতামের কার্যকারিতা সংরক্ষণ করে যেকোনো ব্যবহারকারী ডাটাবেসে রেস্তোরাঁ লিখতে পারেন, কিন্তু একবার একটি রেস্তোরাঁ লেখা হয়ে গেলে তার নাম, অবস্থান, মূল্য এবং বিভাগ পরিবর্তন করা যাবে না। আরও স্পষ্টভাবে বলতে গেলে, শেষ নিয়ম অনুসারে, যেকোনো রেস্তোরাঁ আপডেট অপারেশনের জন্য ডাটাবেসে বিদ্যমান ক্ষেত্রগুলির একই নাম, শহর, মূল্য এবং বিভাগ বজায় রাখা প্রয়োজন।
নিরাপত্তা নিয়মাবলী ব্যবহার করে আপনি কী করতে পারেন সে সম্পর্কে আরও জানতে, ডকুমেন্টেশনটি দেখুন।
9. উপসংহার
এই কোডল্যাবে, আপনি ফায়ারস্টোরের সাহায্যে বেসিক এবং অ্যাডভান্সড রিড এবং রাইট শিখেছেন, সেইসাথে সুরক্ষা নিয়ম ব্যবহার করে ডেটা অ্যাক্সেস কীভাবে সুরক্ষিত করবেন তা শিখেছেন। আপনি codelab-complete শাখায় সম্পূর্ণ সমাধান খুঁজে পেতে পারেন।
ফায়ারস্টোর সম্পর্কে আরও জানতে, নিম্নলিখিত রিসোর্সগুলি দেখুন: