অ্যাপল প্ল্যাটফর্মগুলিতে ডেটা পড়ুন এবং লিখুন

(ঐচ্ছিক) ফায়ারবেস স্থানীয় এমুলেটর স্যুটের সাথে প্রোটোটাইপ এবং পরীক্ষা করুন

আপনার অ্যাপ কীভাবে রিয়েলটাইম ডেটাবেস থেকে পড়ে এবং লেখে সে সম্পর্কে কথা বলার আগে, আসুন এমন একটি সরঞ্জামের সেট পরিচয় করিয়ে দেওয়া যাক যা আপনি প্রোটোটাইপ করতে এবং রিয়েলটাইম ডেটাবেস কার্যকারিতা পরীক্ষা করতে ব্যবহার করতে পারেন: ফায়ারবেস লোকাল এমুলেটর স্যুট। আপনি যদি বিভিন্ন ডেটা মডেল চেষ্টা করে থাকেন, আপনার নিরাপত্তা বিধি অপ্টিমাইজ করে থাকেন, বা ব্যাক-এন্ডের সাথে ইন্টারঅ্যাক্ট করার সবচেয়ে সাশ্রয়ী উপায় খুঁজে বের করার জন্য কাজ করছেন, তাহলে লাইভ পরিষেবাগুলি স্থাপন না করে স্থানীয়ভাবে কাজ করতে সক্ষম হওয়া একটি দুর্দান্ত ধারণা হতে পারে।

একটি রিয়েলটাইম ডাটাবেস এমুলেটর হল স্থানীয় এমুলেটর স্যুটের অংশ, যা আপনার অ্যাপকে আপনার অনুকরণ করা ডাটাবেস সামগ্রী এবং কনফিগারেশনের সাথে ইন্টারঅ্যাক্ট করতে সক্ষম করে, সেইসাথে ঐচ্ছিকভাবে আপনার অনুকরণ করা প্রকল্প সংস্থানগুলি (ফাংশন, অন্যান্য ডেটাবেস এবং নিরাপত্তা নিয়ম)।

রিয়েলটাইম ডেটাবেস এমুলেটর ব্যবহার করার জন্য মাত্র কয়েকটি ধাপ জড়িত:

  1. এমুলেটরের সাথে সংযোগ করতে আপনার অ্যাপের পরীক্ষা কনফিগারে কোডের একটি লাইন যোগ করা হচ্ছে।
  2. আপনার স্থানীয় প্রজেক্ট ডিরেক্টরির রুট থেকে, firebase emulators:start
  3. যথারীতি রিয়েলটাইম ডেটাবেস প্ল্যাটফর্ম SDK ব্যবহার করে বা রিয়েলটাইম ডেটাবেস REST API ব্যবহার করে আপনার অ্যাপের প্রোটোটাইপ কোড থেকে কল করা।

রিয়েলটাইম ডেটাবেস এবং ক্লাউড ফাংশন জড়িত একটি বিস্তারিত ওয়াকথ্রু উপলব্ধ। আপনার স্থানীয় এমুলেটর স্যুট ভূমিকাটিও দেখতে হবে।

একটি FIRDatabaseReference পান

ডাটাবেস থেকে ডেটা পড়তে বা লিখতে, আপনার FIRDatabaseReference এর একটি উদাহরণ প্রয়োজন:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
var ref: DatabaseReference!

ref = Database.database().reference()

উদ্দেশ্য গ

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
@property (strong, nonatomic) FIRDatabaseReference *ref;

self.ref = [[FIRDatabase database] reference];

ডেটা লিখুন

এই দস্তাবেজটি Firebase ডেটা পড়ার এবং লেখার মৌলিক বিষয়গুলিকে কভার করে৷

ফায়ারবেস ডেটা একটি Database রেফারেন্সে লেখা হয় এবং রেফারেন্সের সাথে একটি অ্যাসিঙ্ক্রোনাস লিসেনার সংযুক্ত করে পুনরুদ্ধার করা হয়। শ্রোতা ডেটার প্রাথমিক অবস্থার জন্য একবার ট্রিগার হয় এবং আবার যে কোনও সময় ডেটা পরিবর্তন হয়।

মৌলিক লেখার ক্রিয়াকলাপ

মৌলিক লেখার ক্রিয়াকলাপের জন্য, আপনি একটি নির্দিষ্ট রেফারেন্সে ডেটা সংরক্ষণ করতে setValue ব্যবহার করতে পারেন, সেই পথে বিদ্যমান ডেটা প্রতিস্থাপন করতে পারেন। আপনি এই পদ্ধতিটি ব্যবহার করতে পারেন:

  • নিম্নরূপ উপলব্ধ JSON প্রকারের সাথে সঙ্গতিপূর্ণ পাস প্রকার:
    • NSString
    • NSNumber
    • NSDictionary
    • NSArray

উদাহরণস্বরূপ, আপনি setValue সহ একজন ব্যবহারকারীকে নিম্নরূপ যুক্ত করতে পারেন:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
self.ref.child("users").child(user.uid).setValue(["username": username])

উদ্দেশ্য গ

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
[[[self.ref child:@"users"] child:authResult.user.uid]
    setValue:@{@"username": username}];

এইভাবে setValue ব্যবহার করে যেকোন চাইল্ড নোড সহ নির্দিষ্ট স্থানে ডেটা ওভাররাইট করে। যাইহোক, আপনি এখনও সম্পূর্ণ বস্তুটি পুনরায় লেখা ছাড়াই একটি শিশুকে আপডেট করতে পারেন। আপনি যদি ব্যবহারকারীদের তাদের প্রোফাইল আপডেট করার অনুমতি দিতে চান তবে আপনি নিম্নরূপ ব্যবহারকারীর নাম আপডেট করতে পারেন:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
self.ref.child("users/\(user.uid)/username").setValue(username)

উদ্দেশ্য গ

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
[[[[_ref child:@"users"] child:user.uid] child:@"username"] setValue:username];

ডেটা পড়ুন

মান ইভেন্টের জন্য শুনে ডেটা পড়ুন

একটি পাথে ডেটা পড়তে এবং পরিবর্তনের জন্য শুনতে, FIRDataEventTypeValue ইভেন্টগুলি পর্যবেক্ষণ করতে FIRDatabaseReference observeEventType:withBlock ব্যবহার করুন।

ইভেন্টের ধরণ সাধারণ ব্যবহার
FIRDataEventTypeValue একটি পথের সম্পূর্ণ বিষয়বস্তুর পরিবর্তনের জন্য পড়ুন এবং শুনুন।

আপনি FIRDataEventTypeValue ইভেন্টটি একটি প্রদত্ত পাথে ডেটা পড়ার জন্য ব্যবহার করতে পারেন, কারণ এটি ইভেন্টের সময় বিদ্যমান থাকে। এই পদ্ধতিটি একবার ট্রিগার করা হয় যখন শ্রোতা সংযুক্ত থাকে এবং আবার প্রতিবার ডেটা, যেকোন শিশু সহ, পরিবর্তন হয়। ইভেন্ট কলব্যাক একটি snapshot পাস করা হয় যেখানে শিশু ডেটা সহ সেই অবস্থানের সমস্ত ডেটা রয়েছে৷ যদি কোন ডেটা না থাকে, আপনি যখন exists() কল করবেন তখন স্ন্যাপশট false হবে এবং যখন আপনি এর value বৈশিষ্ট্যটি পড়বেন তখন nil

নিম্নলিখিত উদাহরণটি একটি সামাজিক ব্লগিং অ্যাপ্লিকেশন প্রদর্শন করে যা ডাটাবেস থেকে একটি পোস্টের বিবরণ পুনরুদ্ধার করে:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
refHandle = postRef.observe(DataEventType.value, with: { snapshot in
  // ...
})

উদ্দেশ্য গ

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
_refHandle = [_postRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
  NSDictionary *postDict = snapshot.value;
  // ...
}];

শ্রোতা একটি FIRDataSnapshot পায় যাতে ডাটাবেসের নির্দিষ্ট স্থানে ইভেন্টের সময় তার value বৈশিষ্ট্যে ডেটা থাকে। আপনি মানগুলিকে যথাযথ নেটিভ টাইপের জন্য বরাদ্দ করতে পারেন, যেমন NSDictionary । যদি অবস্থানে কোনো ডেটা বিদ্যমান না থাকে, তাহলে value nil

একবার ডেটা পড়ুন

getData() ব্যবহার করে একবার পড়ুন

আপনার অ্যাপ অনলাইন হোক বা অফলাইন হোক ডাটাবেস সার্ভারের সাথে মিথস্ক্রিয়া পরিচালনা করার জন্য SDK ডিজাইন করা হয়েছে।

সাধারণত, ব্যাকএন্ড থেকে ডেটার আপডেটের বিজ্ঞপ্তি পেতে ডেটা পড়ার জন্য আপনার উপরে বর্ণিত মান ইভেন্ট কৌশলগুলি ব্যবহার করা উচিত। এই কৌশলগুলি আপনার ব্যবহার এবং বিলিং হ্রাস করে এবং আপনার ব্যবহারকারীদের অনলাইন এবং অফলাইনে যাওয়ার সাথে সাথে সেরা অভিজ্ঞতা দেওয়ার জন্য অপ্টিমাইজ করা হয়েছে৷

আপনার যদি শুধুমাত্র একবার ডেটার প্রয়োজন হয়, আপনি ডাটাবেস থেকে ডেটার একটি স্ন্যাপশট পেতে getData() ব্যবহার করতে পারেন। কোনো কারণে getData() সার্ভারের মান ফেরত দিতে অক্ষম হলে, ক্লায়েন্ট স্থানীয় স্টোরেজ ক্যাশে অনুসন্ধান করবে এবং মানটি এখনও খুঁজে না পাওয়া গেলে একটি ত্রুটি ফেরত দেবে।

নিম্নলিখিত উদাহরণটি দেখায় যে ডাটাবেস থেকে একবার ব্যবহারকারীর সর্বজনীন-মুখী ব্যবহারকারীর নাম পুনরুদ্ধার করা:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
do {
  let snapshot = try await ref.child("users/\(uid)/username").getData()
  let userName = snapshot.value as? String ?? "Unknown"
} catch {
  print(error)
}

উদ্দেশ্য গ

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
NSString *userPath = [NSString stringWithFormat:@"users/%@/username", uid];
[[ref child:userPath] getDataWithCompletionBlock:^(NSError * _Nullable error, FIRDataSnapshot * _Nonnull snapshot) {
  if (error) {
    NSLog(@"Received an error %@", error);
    return;
  }
  NSString *userName = snapshot.value;
}];

getData() এর অপ্রয়োজনীয় ব্যবহার ব্যান্ডউইথের ব্যবহার বাড়াতে পারে এবং কর্মক্ষমতা হারাতে পারে, যা উপরে দেখানো হিসাবে রিয়েলটাইম লিসেনার ব্যবহার করে প্রতিরোধ করা যেতে পারে।

পর্যবেক্ষকের সাথে একবার ডেটা পড়ুন

কিছু ক্ষেত্রে আপনি সার্ভারে একটি আপডেট করা মান পরীক্ষা করার পরিবর্তে স্থানীয় ক্যাশে থেকে মান অবিলম্বে ফেরত দিতে চাইতে পারেন। এই ক্ষেত্রে আপনি অবিলম্বে স্থানীয় ডিস্ক ক্যাশে থেকে ডেটা পেতে observeSingleEventOfType ব্যবহার করতে পারেন।

এটি এমন ডেটার জন্য উপযোগী যেগুলি শুধুমাত্র একবার লোড করতে হবে এবং ঘন ঘন পরিবর্তন হবে বলে আশা করা হয় না বা সক্রিয় শোনার প্রয়োজন হয় না। উদাহরণস্বরূপ, পূর্ববর্তী উদাহরণগুলিতে ব্লগিং অ্যাপটি ব্যবহারকারীর প্রোফাইল লোড করতে এই পদ্ধতিটি ব্যবহার করে যখন তারা একটি নতুন পোস্ট লিখতে শুরু করে:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
let userID = Auth.auth().currentUser?.uid
ref.child("users").child(userID!).observeSingleEvent(of: .value, with: { snapshot in
  // Get user value
  let value = snapshot.value as? NSDictionary
  let username = value?["username"] as? String ?? ""
  let user = User(username: username)

  // ...
}) { error in
  print(error.localizedDescription)
}

উদ্দেশ্য গ

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
NSString *userID = [FIRAuth auth].currentUser.uid;
[[[_ref child:@"users"] child:userID] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
  // Get user value
  User *user = [[User alloc] initWithUsername:snapshot.value[@"username"]];

  // ...
} withCancelBlock:^(NSError * _Nonnull error) {
  NSLog(@"%@", error.localizedDescription);
}];

ডেটা আপডেট করা বা মুছে ফেলা

নির্দিষ্ট ক্ষেত্র আপডেট করুন

একই সাথে অন্যান্য চাইল্ড নোড ওভাররাইট না করে একটি নোডের নির্দিষ্ট শিশুদের কাছে লিখতে, updateChildValues ​​পদ্ধতি ব্যবহার করুন।

updateChildValues ​​কল করার সময়, আপনি কীটির জন্য একটি পাথ নির্দিষ্ট করে নিম্ন-স্তরের চাইল্ড মান আপডেট করতে পারেন। যদি আরও ভাল স্কেল করার জন্য একাধিক স্থানে ডেটা সংরক্ষণ করা হয়, আপনি ডেটা ফ্যান-আউট ব্যবহার করে সেই ডেটার সমস্ত দৃষ্টান্ত আপডেট করতে পারেন। উদাহরণস্বরূপ, একটি সামাজিক ব্লগিং অ্যাপ একটি পোস্ট তৈরি করতে এবং একই সাথে সাম্প্রতিক কার্যকলাপ ফিড এবং পোস্টিং ব্যবহারকারীর কার্যকলাপ ফিডে আপডেট করতে চাইতে পারে৷ এটি করার জন্য, ব্লগিং অ্যাপ্লিকেশন এই মত কোড ব্যবহার করে:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
guard let key = ref.child("posts").childByAutoId().key else { return }
let post = ["uid": userID,
            "author": username,
            "title": title,
            "body": body]
let childUpdates = ["/posts/\(key)": post,
                    "/user-posts/\(userID)/\(key)/": post]
ref.updateChildValues(childUpdates)

উদ্দেশ্য গ

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
NSString *key = [[_ref child:@"posts"] childByAutoId].key;
NSDictionary *post = @{@"uid": userID,
                       @"author": username,
                       @"title": title,
                       @"body": body};
NSDictionary *childUpdates = @{[@"/posts/" stringByAppendingString:key]: post,
                               [NSString stringWithFormat:@"/user-posts/%@/%@/", userID, key]: post};
[_ref updateChildValues:childUpdates];

এই উদাহরণটি /posts/$postid এ সমস্ত ব্যবহারকারীর জন্য পোস্ট সম্বলিত নোডে একটি পোস্ট তৈরি করতে childByAutoId ব্যবহার করে এবং একই সাথে getKey() দিয়ে কী পুনরুদ্ধার করে। কীটি তারপর /user-posts/$userid/$postid এ ব্যবহারকারীর পোস্টে একটি দ্বিতীয় এন্ট্রি তৈরি করতে ব্যবহার করা যেতে পারে।

এই পথগুলি ব্যবহার করে, আপনি updateChildValues জন্য একক কলের মাধ্যমে JSON ট্রিতে একাধিক অবস্থানে একযোগে আপডেটগুলি সম্পাদন করতে পারেন, যেমন এই উদাহরণটি কীভাবে উভয় স্থানেই নতুন পোস্ট তৈরি করে৷ এইভাবে করা যুগপত আপডেটগুলি পরমাণু: হয় সমস্ত আপডেট সফল হয় বা সমস্ত আপডেট ব্যর্থ হয়।

একটি সমাপ্তি ব্লক যোগ করুন

আপনি যদি জানতে চান আপনার ডেটা কখন প্রতিশ্রুতিবদ্ধ হয়েছে, আপনি একটি সমাপ্তি ব্লক যোগ করতে পারেন। setValue এবং updateChildValues ​​উভয়ই একটি ঐচ্ছিক সমাপ্তি ব্লক নেয় যা ডাটাবেসের সাথে লেখার প্রতিশ্রুতিবদ্ধ হলে বলা হয়। কোন ডেটা সংরক্ষণ করা হয়েছে এবং কোন ডেটা এখনও সিঙ্ক্রোনাইজ করা হচ্ছে তা ট্র্যাক রাখার জন্য এই শ্রোতা উপযোগী হতে পারে। যদি কলটি ব্যর্থ হয়, তাহলে শ্রোতাকে একটি ত্রুটি অবজেক্ট পাস করা হয় যা নির্দেশ করে যে কেন ব্যর্থতা ঘটেছে।

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
do {
  try await ref.child("users").child(user.uid).setValue(["username": username])
  print("Data saved successfully!")
} catch {
  print("Data could not be saved: \(error).")
}

উদ্দেশ্য গ

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
[[[_ref child:@"users"] child:user.uid] setValue:@{@"username": username} withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  if (error) {
    NSLog(@"Data could not be saved: %@", error);
  } else {
    NSLog(@"Data saved successfully.");
  }
}];

ডেটা মুছুন

ডেটা মুছে ফেলার সহজ উপায় হল সেই ডেটার অবস্থানের রেফারেন্সে removeValue কল করা।

আপনি setValue বা updateChildValues মতো অন্য লেখার অপারেশনের মান হিসাবে nil উল্লেখ করেও মুছে ফেলতে পারেন। আপনি একটি একক API কলে একাধিক শিশু মুছে ফেলার জন্য updateChildValues এর সাথে এই কৌশলটি ব্যবহার করতে পারেন।

শ্রোতাদের বিচ্ছিন্ন করুন

আপনি যখন ViewController ছেড়ে যান তখন পর্যবেক্ষকরা স্বয়ংক্রিয়ভাবে ডেটা সিঙ্ক করা বন্ধ করে না। যদি একটি পর্যবেক্ষক সঠিকভাবে সরানো না হয়, তবে এটি স্থানীয় মেমরিতে ডেটা সিঙ্ক করতে থাকে। যখন একজন পর্যবেক্ষকের আর প্রয়োজন হয় না, তখন সংশ্লিষ্ট FIRDatabaseHandle টিকে removeObserverWithHandle পদ্ধতিতে পাস করে এটি সরিয়ে ফেলুন।

আপনি যখন একটি রেফারেন্সে একটি কলব্যাক ব্লক যোগ করেন, একটি FIRDatabaseHandle ফেরত দেওয়া হয়। এই হ্যান্ডেলগুলি কলব্যাক ব্লক অপসারণ করতে ব্যবহার করা যেতে পারে।

যদি একটি ডাটাবেস রেফারেন্সে একাধিক শ্রোতা যোগ করা হয়, একটি ইভেন্ট উত্থাপিত হলে প্রতিটি শ্রোতাকে ডাকা হয়। সেই অবস্থানে ডেটা সিঙ্ক করা বন্ধ করার জন্য, আপনাকে removeAllObservers পদ্ধতিতে কল করে একটি অবস্থানের সমস্ত পর্যবেক্ষককে সরিয়ে ফেলতে হবে।

removeObserverWithHandle বা removeAllObservers শ্রোতার উপর কল করা স্বয়ংক্রিয়ভাবে তার চাইল্ড নোডে নিবন্ধিত শ্রোতাদের সরিয়ে দেয় না; সেগুলি অপসারণ করার জন্য আপনাকে অবশ্যই সেই রেফারেন্স বা হ্যান্ডেলগুলির ট্র্যাক রাখতে হবে।

লেনদেন হিসাবে ডেটা সংরক্ষণ করুন

ক্রমবর্ধমান কাউন্টারগুলির মতো সমসাময়িক পরিবর্তন দ্বারা দূষিত হতে পারে এমন ডেটা নিয়ে কাজ করার সময়, আপনি একটি লেনদেন অপারেশন ব্যবহার করতে পারেন। আপনি এই অপারেশনটিকে দুটি আর্গুমেন্ট দেন: একটি আপডেট ফাংশন এবং একটি ঐচ্ছিক সমাপ্তি কলব্যাক৷ আপডেট ফাংশন একটি যুক্তি হিসাবে ডেটার বর্তমান অবস্থা নেয় এবং আপনি লিখতে চান এমন নতুন পছন্দসই অবস্থা প্রদান করে।

উদাহরণস্বরূপ, সোশ্যাল ব্লগিং অ্যাপের উদাহরণে, আপনি ব্যবহারকারীদের পোস্ট স্টার এবং আনস্টার করার অনুমতি দিতে পারেন এবং একটি পোস্ট কতগুলি স্টার পেয়েছে তার ট্র্যাক রাখতে পারেন:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
ref.runTransactionBlock({ (currentData: MutableData) -> TransactionResult in
  if var post = currentData.value as? [String: AnyObject],
    let uid = Auth.auth().currentUser?.uid {
    var stars: [String: Bool]
    stars = post["stars"] as? [String: Bool] ?? [:]
    var starCount = post["starCount"] as? Int ?? 0
    if let _ = stars[uid] {
      // Unstar the post and remove self from stars
      starCount -= 1
      stars.removeValue(forKey: uid)
    } else {
      // Star the post and add self to stars
      starCount += 1
      stars[uid] = true
    }
    post["starCount"] = starCount as AnyObject?
    post["stars"] = stars as AnyObject?

    // Set value and report transaction success
    currentData.value = post

    return TransactionResult.success(withValue: currentData)
  }
  return TransactionResult.success(withValue: currentData)
}) { error, committed, snapshot in
  if let error = error {
    print(error.localizedDescription)
  }
}

উদ্দেশ্য গ

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
[ref runTransactionBlock:^FIRTransactionResult * _Nonnull(FIRMutableData * _Nonnull currentData) {
  NSMutableDictionary *post = currentData.value;
  if (!post || [post isEqual:[NSNull null]]) {
    return [FIRTransactionResult successWithValue:currentData];
  }

  NSMutableDictionary *stars = post[@"stars"];
  if (!stars) {
    stars = [[NSMutableDictionary alloc] initWithCapacity:1];
  }
  NSString *uid = [FIRAuth auth].currentUser.uid;
  int starCount = [post[@"starCount"] intValue];
  if (stars[uid]) {
    // Unstar the post and remove self from stars
    starCount--;
    [stars removeObjectForKey:uid];
  } else {
    // Star the post and add self to stars
    starCount++;
    stars[uid] = @YES;
  }
  post[@"stars"] = stars;
  post[@"starCount"] = @(starCount);

  // Set value and report transaction success
  currentData.value = post;
  return [FIRTransactionResult successWithValue:currentData];
} andCompletionBlock:^(NSError * _Nullable error,
                       BOOL committed,
                       FIRDataSnapshot * _Nullable snapshot) {
  // Transaction completed
  if (error) {
    NSLog(@"%@", error.localizedDescription);
  }
}];

একটি লেনদেন ব্যবহার করা স্টার গণনাকে ভুল হতে বাধা দেয় যদি একাধিক ব্যবহারকারী একই পোস্টে একই সময়ে স্টার করেন বা ক্লায়েন্টের পুরানো ডেটা থাকে। FIRMutableData শ্রেণীতে থাকা মানটি প্রাথমিকভাবে পথের জন্য ক্লায়েন্টের সর্বশেষ পরিচিত মান, অথবা কোনোটি না থাকলে nil । সার্ভার তার বর্তমান মানের সাথে প্রারম্ভিক মান তুলনা করে এবং মান মেলে বা প্রত্যাখ্যান করলে লেনদেন গ্রহণ করে। যদি লেনদেন প্রত্যাখ্যান করা হয়, সার্ভার ক্লায়েন্টকে বর্তমান মান ফেরত দেয়, যা আপডেট করা মান দিয়ে আবার লেনদেন চালায়। লেনদেন গৃহীত না হওয়া পর্যন্ত বা অনেক প্রচেষ্টা করা না হওয়া পর্যন্ত এটি পুনরাবৃত্তি হয়।

পারমাণবিক সার্ভার-সাইড বৃদ্ধি

উপরোক্ত ব্যবহারের ক্ষেত্রে আমরা ডাটাবেসে দুটি মান লিখছি: পোস্টে তারকাচিহ্নিত/তারামুক্তকারী ব্যবহারকারীর আইডি এবং বর্ধিত তারকা গণনা। যদি আমরা ইতিমধ্যেই জানি যে ব্যবহারকারী পোস্টটি তারকাচিহ্নিত করছে, আমরা একটি লেনদেনের পরিবর্তে একটি পারমাণবিক বৃদ্ধি অপারেশন ব্যবহার করতে পারি।

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
let updates = [
  "posts/\(postID)/stars/\(userID)": true,
  "posts/\(postID)/starCount": ServerValue.increment(1),
  "user-posts/\(postID)/stars/\(userID)": true,
  "user-posts/\(postID)/starCount": ServerValue.increment(1)
] as [String : Any]
Database.database().reference().updateChildValues(updates)

উদ্দেশ্য গ

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
NSDictionary *updates = @{[NSString stringWithFormat: @"posts/%@/stars/%@", postID, userID]: @TRUE,
                        [NSString stringWithFormat: @"posts/%@/starCount", postID]: [FIRServerValue increment:@1],
                        [NSString stringWithFormat: @"user-posts/%@/stars/%@", postID, userID]: @TRUE,
                        [NSString stringWithFormat: @"user-posts/%@/starCount", postID]: [FIRServerValue increment:@1]};
[[[FIRDatabase database] reference] updateChildValues:updates];

এই কোড একটি লেনদেন অপারেশন ব্যবহার করে না, তাই এটি স্বয়ংক্রিয়ভাবে পুনরায় চালানো হয় না যদি একটি বিরোধপূর্ণ আপডেট থাকে। যাইহোক, যেহেতু ইনক্রিমেন্ট অপারেশন সরাসরি ডাটাবেস সার্ভারে ঘটে, তাই বিরোধের কোন সুযোগ নেই।

আপনি যদি অ্যাপ্লিকেশান-নির্দিষ্ট দ্বন্দ্বগুলি সনাক্ত করতে এবং প্রত্যাখ্যান করতে চান, যেমন কোনও ব্যবহারকারী একটি পোস্টে তারকাচিহ্নিত একটি পোস্ট যা তারা ইতিমধ্যেই তারকাচিহ্নিত করেছে, আপনার সেই ব্যবহারের ক্ষেত্রে কাস্টম নিরাপত্তা নিয়ম লিখতে হবে।

অফলাইনে ডেটা নিয়ে কাজ করুন

যদি কোনো ক্লায়েন্ট তার নেটওয়ার্ক সংযোগ হারিয়ে ফেলে, তাহলে আপনার অ্যাপ সঠিকভাবে কাজ করতে থাকবে।

ফায়ারবেস ডাটাবেসের সাথে সংযুক্ত প্রতিটি ক্লায়েন্ট যেকোনো সক্রিয় ডেটার নিজস্ব অভ্যন্তরীণ সংস্করণ বজায় রাখে। যখন ডেটা লেখা হয়, এটি প্রথমে এই স্থানীয় সংস্করণে লেখা হয়। ফায়ারবেস ক্লায়েন্ট তারপর সেই ডেটাটিকে দূরবর্তী ডাটাবেস সার্ভারের সাথে এবং অন্যান্য ক্লায়েন্টদের সাথে "সর্বোত্তম প্রচেষ্টা" ভিত্তিতে সিঙ্ক্রোনাইজ করে।

ফলস্বরূপ, সার্ভারে কোনো ডেটা লেখার আগে সমস্ত ডাটাবেসে লিখলে তাৎক্ষণিকভাবে স্থানীয় ইভেন্ট ট্রিগার করে। এর মানে নেটওয়ার্ক লেটেন্সি বা সংযোগ নির্বিশেষে আপনার অ্যাপ প্রতিক্রিয়াশীল থাকে।

একবার সংযোগ পুনঃস্থাপিত হলে, আপনার অ্যাপ ইভেন্টের উপযুক্ত সেট পায় যাতে ক্লায়েন্ট বর্তমান সার্ভারের অবস্থার সাথে সিঙ্ক করে, কোনো কাস্টম কোড না লিখেই।

আমরা অনলাইন এবং অফলাইন ক্ষমতা সম্পর্কে আরও জানুন- এ অফলাইন আচরণ সম্পর্কে আরও কথা বলব৷

পরবর্তী পদক্ষেপ