ডেটা পড়ুন এবং লিখুন

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

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

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

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

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

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

একটি ডেটাবেস রেফারেন্স পান

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

DatabaseReference ref = FirebaseDatabase.instance.ref();

ডেটা লিখুন

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

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

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

মৌলিক লেখার ক্রিয়াকলাপের জন্য, আপনি একটি নির্দিষ্ট রেফারেন্সে ডেটা সংরক্ষণ করতে set() ব্যবহার করতে পারেন, সেই পথে বিদ্যমান ডেটা প্রতিস্থাপন করতে পারেন। আপনি নিম্নলিখিত ধরনের একটি রেফারেন্স সেট করতে পারেন: String , boolean , int , double , Map , List

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

DatabaseReference ref = FirebaseDatabase.instance.ref("users/123");

await ref.set({
  "name": "John",
  "age": 18,
  "address": {
    "line1": "100 Mountain View"
  }
});

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

DatabaseReference ref = FirebaseDatabase.instance.ref("users/123");

// Only update the name, leave the age and address!
await ref.update({
  "age": 19,
});

update() পদ্ধতিটি নোডের একটি সাব-পাথ গ্রহণ করে, যা আপনাকে একবারে ডাটাবেসে একাধিক নোড আপডেট করতে দেয়:

DatabaseReference ref = FirebaseDatabase.instance.ref("users");

await ref.update({
  "123/age": 19,
  "123/address/line1": "1 Mountain View",
});

ডেটা পড়ুন

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

একটি পাথে ডেটা পড়তে এবং পরিবর্তনগুলি শুনতে, DatabaseEvent s শোনার জন্য DatabaseReference এর onValue বৈশিষ্ট্যটি ব্যবহার করুন৷

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

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

DatabaseReference starCountRef =
        FirebaseDatabase.instance.ref('posts/$postId/starCount');
starCountRef.onValue.listen((DatabaseEvent event) {
    final data = event.snapshot.value;
    updateStarCount(data);
});

শ্রোতা একটি DataSnapshot পায় যাতে ডাটাবেসের নির্দিষ্ট অবস্থানের ডেটা থাকে তার value সম্পত্তিতে ইভেন্টের সময়।

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

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

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

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

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

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

final ref = FirebaseDatabase.instance.ref();
final snapshot = await ref.child('users/$userId').get();
if (snapshot.exists) {
    print(snapshot.value);
} else {
    print('No data available.');
}

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

একবারের সাথে একবার ডেটা পড়ুন()

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

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

final event = await ref.once(DatabaseEventType.value);
final username = event.snapshot.value?.username ?? 'Anonymous';

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

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

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

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

void writeNewPost(String uid, String username, String picture, String title,
        String body) async {
    // A post entry.
    final postData = {
        'author': username,
        'uid': uid,
        'body': body,
        'title': title,
        'starCount': 0,
        'authorPic': picture,
    };

    // Get a key for a new Post.
    final newPostKey =
        FirebaseDatabase.instance.ref().child('posts').push().key;

    // Write the new post's data simultaneously in the posts list and the
    // user's post list.
    final Map<String, Map> updates = {};
    updates['/posts/$newPostKey'] = postData;
    updates['/user-posts/$uid/$newPostKey'] = postData;

    return FirebaseDatabase.instance.ref().update(updates);
}

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

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

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

আপনি যদি জানতে চান আপনার ডেটা কখন প্রতিশ্রুতিবদ্ধ হয়েছে, আপনি সম্পূর্ণ কলব্যাক নিবন্ধন করতে পারেন। set() এবং update() উভয়ই Future s ফেরত দেয়, যেখানে আপনি সফলতা এবং ত্রুটি কলব্যাকগুলি সংযুক্ত করতে পারেন যেগুলি ডাটাবেসে লেখার প্রতিশ্রুতিবদ্ধ হওয়ার সময় কল করা হয় এবং যখন কলটি ব্যর্থ হয়।

FirebaseDatabase.instance
    .ref('users/$userId/email')
    .set(emailAddress)
    .then((_) {
        // Data saved successfully!
    })
    .catchError((error) {
        // The write failed...
    });

ডেটা মুছুন

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

আপনি set() বা update() মতো অন্য লেখার অপারেশনের মান হিসাবে null উল্লেখ করেও মুছে ফেলতে পারেন। আপনি একটি একক API কলে একাধিক শিশু মুছে ফেলার জন্য update() দিয়ে এই কৌশলটি ব্যবহার করতে পারেন।

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

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

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

void toggleStar(String uid) async {
  DatabaseReference postRef =
      FirebaseDatabase.instance.ref("posts/foo-bar-123");

  TransactionResult result = await postRef.runTransaction((Object? post) {
    // Ensure a post at the ref exists.
    if (post == null) {
      return Transaction.abort();
    }

    Map<String, dynamic> _post = Map<String, dynamic>.from(post as Map);
    if (_post["stars"] is Map && _post["stars"][uid] != null) {
      _post["starCount"] = (_post["starCount"] ?? 1) - 1;
      _post["stars"][uid] = null;
    } else {
      _post["starCount"] = (_post["starCount"] ?? 0) + 1;
      if (!_post.containsKey("stars")) {
        _post["stars"] = {};
      }
      _post["stars"][uid] = true;
    }

    // Return the new data.
    return Transaction.success(_post);
  });
}

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

await ref.runTransaction((Object? post) {
  // ...
}, applyLocally: false);

একটি লেনদেনের ফলাফল হল একটি TransactionResult , যাতে তথ্য থাকে যেমন লেনদেনটি করা হয়েছে কিনা এবং নতুন স্ন্যাপশট:

DatabaseReference ref = FirebaseDatabase.instance.ref("posts/123");

TransactionResult result = await ref.runTransaction((Object? post) {
  // ...
});

print('Committed? ${result.committed}'); // true / false
print('Snapshot? ${result.snapshot}'); // DataSnapshot

একটি লেনদেন বাতিল করা হচ্ছে

আপনি যদি নিরাপদে একটি লেনদেন বাতিল করতে চান, তাহলে একটি AbortTransactionException নিক্ষেপ করতে Transaction.abort() এ কল করুন:

TransactionResult result = await ref.runTransaction((Object? user) {
  if (user !== null) {
    return Transaction.abort();
  }

  // ...
});

print(result.committed); // false

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

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

void addStar(uid, key) async {
  Map<String, Object?> updates = {};
  updates["posts/$key/stars/$uid"] = true;
  updates["posts/$key/starCount"] = ServerValue.increment(1);
  updates["user-posts/$key/stars/$uid"] = true;
  updates["user-posts/$key/starCount"] = ServerValue.increment(1);
  return FirebaseDatabase.instance.ref().update(updates);
}

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

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

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

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

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

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

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

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

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