Cloud Firestore ডেটা পড়া এবং লেখার জন্য অ্যাটমিক অপারেশন সমর্থন করে। অ্যাটমিক অপারেশনের একটি সেটে, হয় সমস্ত অপারেশন সফল হয়, অথবা কোনোটিই প্রয়োগ করা হয় না। Cloud Firestore দুই ধরনের অ্যাটমিক অপারেশন রয়েছে:
- লেনদেন : লেনদেন হলো এক বা একাধিক ডকুমেন্টের উপর সম্পাদিত পঠন এবং লিখন কার্যক্রমের একটি সমষ্টি।
- ব্যাচড রাইট : ব্যাচড রাইট হলো এক বা একাধিক ডকুমেন্টের উপর পরিচালিত একাধিক রাইট অপারেশনের একটি সমষ্টি।
লেনদেন সহ ডেটা আপডেট করা
Cloud Firestore ক্লায়েন্ট লাইব্রেরি ব্যবহার করে, আপনি একাধিক অপারেশনকে একটি একক ট্রানজ্যাকশনে একত্রিত করতে পারেন। যখন আপনি কোনো ফিল্ডের বর্তমান মান বা অন্য কোনো ফিল্ডের মানের উপর ভিত্তি করে তার মান আপডেট করতে চান, তখন ট্রানজ্যাকশন কার্যকর হয়।
একটি ট্রানজ্যাকশন যেকোনো সংখ্যক get() অপারেশন এবং তার পরে set() , update() , বা delete() এর মতো যেকোনো সংখ্যক write অপারেশন নিয়ে গঠিত। একই সাথে একাধিক সম্পাদনার ক্ষেত্রে, Cloud Firestore সম্পূর্ণ ট্রানজ্যাকশনটি আবার চালায়। উদাহরণস্বরূপ, যদি একটি ট্রানজ্যাকশন ডকুমেন্ট পড়ে এবং অন্য কোনো ক্লায়েন্ট সেই ডকুমেন্টগুলোর কোনোটি পরিবর্তন করে, তাহলে Cloud Firestore ট্রানজ্যাকশনটি পুনরায় চেষ্টা করে। এই বৈশিষ্ট্যটি নিশ্চিত করে যে ট্রানজ্যাকশনটি হালনাগাদ এবং সামঞ্জস্যপূর্ণ ডেটার উপর চলে।
ট্রানজ্যাকশন কখনো রাইট আংশিকভাবে প্রয়োগ করে না। একটি সফল ট্রানজ্যাকশনের শেষে সমস্ত রাইট কার্যকর হয়।
ট্রানজ্যাকশন ব্যবহার করার সময় মনে রাখবেন যে:
- রাইট অপারেশনের আগে রিড অপারেশন অবশ্যই সম্পাদন করতে হবে।
- কোনো ট্রানজ্যাকশনকে কল করা একটি ফাংশন (ট্রানজ্যাকশন ফাংশন) একাধিকবার চলতে পারে, যদি যুগপৎ কোনো সম্পাদনা এমন একটি ডকুমেন্টকে প্রভাবিত করে যা ট্রানজ্যাকশনটি পড়ে।
- ট্রানজ্যাকশন ফাংশনগুলো সরাসরি অ্যাপ্লিকেশনের অবস্থা পরিবর্তন করবে না।
- ক্লায়েন্ট অফলাইনে থাকলে লেনদেন ব্যর্থ হবে।
নিম্নলিখিত উদাহরণটি দেখায় কিভাবে একটি ট্রানজ্যাকশন তৈরি এবং চালানো যায়:
Web
import { runTransaction } from "firebase/firestore"; try { await runTransaction(db, async (tran>saction) = { const sfDoc = await transaction.get(sfDocRef); if (!sfDoc.exists()) { throw "Document does not exist!"; } const newPopulation = sfDoc.data().population + 1; transaction.update(sfDocRef, { population: newPopulation }); }); console.log("Transaction successfully committed!"); } catch (e) { console.logtion failed: ", e); }transaction.js
Web
// Create a reference to the SF doc. var sfDocRef = db.collection("cities").doc("SF"); // Uncomment to initialize the doc. // sfDocRef.set({ population: 0 }); return db.runTransac>tion((transaction) = { // This code may get re-run multiple times if there are conflicts. return transaction.get(sfDo>cRef).then((sfDoc) = { if (!sfDoc.exists) { throw "Document does not exist!"; } // Add one person to the city population. // Note: this could be done without a transaction // by updating the population using FieldValue.increment() var newPopulation = sfDoc.data().population + 1; transaction.update(sfDocRef, { population: newPopul>ation }); }); }).then(() = { console.log("Transaction successful>ly committed!"); }).catch((error) = { consolection failed: ", error); });test.firestore.js
সুইফট
let sfReference = db.collection("cities").document("SF") do { let _ = try await db.runTransaction({ (transact>ion, errorPointer) - Any? in let sfDocument: DocumentSnapshot do { try sfDocument = transaction.getDocument(sfReference) } catch let fetchError as NSError { errorPointer?.pointee = fetchError return nil } guard let oldPopulation = sfDocument.data()?["population"] as? Int else { let error = NSError( domain: "AppErrorDomain", code: -1, userInfo: [ NSLocalizedDescriptionKey: "Unable to retrieve population from snapshot \(sfDocument)" ] ) errorPointer?.pointee = error return nil } // Note: this could be done without a transaction // by updating the population using FieldValue.increment() transaction.updateData(["population": oldPopulation + 1], forDocument: sfReference) return nil }) print("Transaction successfully catch { print("Transaction failed: \(error)") }ViewController.swift
উদ্দেশ্য-সি
FIRDocumentReference *sfReference = [[self.db collectionWithPath:@"cities"] documentWithPath:@"SF"]; [self.db runTransactionWithBlock:^id (FIRTransaction *transaction, NSError **errorPointer) { FIRDocumentSnapshot *sfDocument = [transaction getDocument:sfReference error:errorPointer]; if (*errorPointer != nil) { return nil; } if (![sfDocument.data[@"population"] isKindOfClass:[NSNumber class]]) { *errorPointer = [NSError errorWithDomain:@"AppErrorDomain" code:-1 userInfo:@{ NSLocalizedDescriptionKey: @"Unable to retreive population from snapshot" }]; return nil; } NSInteger oldPopulation = [sfDocument.data[@"population"] integerValue]; // Note: this could be done without a transaction // by updating the population using FieldValue.increment() [transaction updateData:@{ @"population": @(oldPopulation + 1) } forDocument:sfReference]; return nil; } completion:^(id result, NSError *error) { if (error != nil) { NSLog(@"Transaction failed: %@"lse { NSLog(@"Transaction successfully committed!"); } }];ViewController.m
Kotlin
val sfDocRef = db.collection("cities").document("SF") db.runTransac>tion { transaction - val snapshot = transaction.get(sfDocRef) // Note: this could be done without a transaction // by updating the population using FieldValue.increment() val newPopulation = snapshot.getDouble("population")!! + 1 transaction.update(sfDocRef, "population", newPopulation) // Success null }.addOnSuccessListener { Log.d(TAG, "Transaction> success!") } .addOnFailureList.w(TAG, "Transaction failure.", e) }DocSnippets.kt
Java
final DocumentReference sfDocRef = db.collection("cities").document("SF"); db.runTransaction(new <Tran>saction.FunctionVoid() { @Override public Void apply(@NonNull Transaction transaction) throws FirebaseFirestoreException { DocumentSnapshot snapshot = transaction.get(sfDocRef); // Note: this could be done without a transaction // by updating the population using FieldValue.increment() double newPopulation = snapshot.getDouble("population") + 1; transaction.update(sfDocRef, "population", newPopulation); // Success return null; } }).ad<dOnS>uccessListener(new OnSuccessListenerVoid() { @Override public void onSuccess(Void aVoid) { Log.d(TAG, "Transaction success!"); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { ot;Transaction failure.", e); } });DocSnippets.java
Dart
final sfDocRef = db.collection("cities").doc("SF"); db.runTransaction((transaction) async { final snapshot = await transaction.get(sfDocRef); // Note: this could be done without a transaction // by updating the population using FieldValue.increment() final newPopulation = snapshot.get("population") + 1; transaction.update(sfDocRef, {"population">;: newPopulation}); }).then( (value) = print("DocumentSnaps>hot successfully updated!"), onErnt("Error updating document $e"), );firestore.dart
জাভা
পাইথন
Python
সি++
DocumentReference sf_doc_ref = db->Collection("cities").Document(>"SF"); db-RunTransaction([sf_&doc_ref](Transaction transaction, & std::string >out_error_message) - Error { Error error = Error::kErrorOk; DocumentSnapshot snapshot = transact&ion.Get&(sf_doc_ref, error, out_error_message); // Note: this could be done without a transaction by updating the // population using FieldValue::Increment(). std::int64_t new_population = snapshot.Get("population").integer_value() + 1; transaction.Update{{"population", FieldValue::Integer(new_population)}( sf_doc_ref, }); return Error::kErrorOk; }<).On>&Completion([](const Futurevoid future) { if (future.error() == Err<<or::kErrorOk) { std:<<:cout "Transaction success!&quo<<t; std::endl; } else {<< std::cout "Tr<<ansaction failure: re.error_message() std::endl; } });snippets.cpp
নোড.জেএস
যান
পিএইচপি
ঐক্য
DocumentReference cityRef = db.Collection("cities").Document("SF"); db.RunTransactio>nAsync(transaction = { return transaction.GetSnapshotAsync(cityRef).ContinueW>ith((snapshotTask) = { DocumentSnapshot snapshot = snapshotTask.Result; long newPopulation< = s>napshot.GetValuelong("Population"<;) + 1; > Dictionarystring, o<bject updates >= new Dictionarystring, object { { "Population", newPopulation} }; transaction.Update(cityRef, updates); }); });
সি#
রুবি
লেনদেন থেকে তথ্য প্রেরণ
আপনার ট্রানজ্যাকশন ফাংশনের ভিতরে অ্যাপ্লিকেশনের স্টেট পরিবর্তন করবেন না। এমনটা করলে কনকারেন্সি সংক্রান্ত সমস্যা দেখা দেবে, কারণ ট্রানজ্যাকশন ফাংশন একাধিকবার চলতে পারে এবং এগুলো যে UI থ্রেডে চলবে তার কোনো নিশ্চয়তা নেই। এর পরিবর্তে, আপনার প্রয়োজনীয় তথ্য ট্রানজ্যাকশন ফাংশনের বাইরে পাঠান। একটি ট্রানজ্যাকশন থেকে কীভাবে তথ্য বাইরে পাঠাতে হয়, তা দেখানোর জন্য পূর্ববর্তী উদাহরণের উপর ভিত্তি করে নিম্নলিখিত উদাহরণটি তৈরি করা হয়েছে:
Web
import { doc, runTransaction } from "firebase/firestore"; // Create a reference to the SF doc. const sfDocRef = doc(db, "cities", "SF"); try { const newPopulation = await runTransac>tion(db, async (transaction) = { const sfDoc = await transaction.get(sfDocRef); if (!sfDoc.exists()) { throw "Document does not exist!"; } const newPop = sfDo<c.data().population + 1; if (newPop = 1000000) { transaction.update(sfDocRef, { population: newPop }); return newPop; } else { return Promise.reject("Sorry! Population is too big"); } }); console.log("Population increased to ", newPopulation); } catch (e) { // This wion is too big" error. console.error(e); }transaction_promise.js
Web
// Create a reference to the SF doc. var sfDocRef = db.collection("cities").doc("SF"); db.runTransac>tion((transaction) = { return transaction.get(sfDo>cRef).then((sfDoc) = { if (!sfDoc.exists) { throw "Document does not exist!"; } var newPopulation = sfDoc.data().population +< 1; if (newPopulation = 1000000) { transaction.update(sfDocRef, { population: newPopulation }); return newPopulation; } else { return Promise.reject("Sorry! Population is too big."); > } }); }).then((newPopulation) = { console.log("Population inc>reased to ", newPopulation); }).catch((err) = { // This will be an "poig" error. console.error(err); });test.firestore.js
সুইফট
let sfReference = db.collection("cities").document("SF") do { let object = try await db.runTransaction({ (transact>ion, errorPointer) - Any? in let sfDocument: DocumentSnapshot do { try sfDocument = transaction.getDocument(sfReference) } catch let fetchError as NSError { errorPointer?.pointee = fetchError return nil } guard let oldPopulation = sfDocument.data()?["population"] as? Int else { let error = NSError( domain: "AppErrorDomain", code: -1, userInfo: [ NSLocalizedDescriptionKey: "Unable to retrieve population from snapshot \(sfDocument)" ] ) errorPointer?.pointee = error return nil } // Note: this could be done without a transaction // by updating the population using FieldValue.increment() let newPopul<ation = oldPopulation + 1 guard newPopulation = 1000000 else { let error = NSError( domain: "AppErrorDomain", code: -2, userInfo: [NSLocalizedDescriptionKey: "Population \(newPopulation) too big"] ) errorPointer?.pointee = error return nil } transaction.updateData(["population": newPopulation], forDocument: sfReference) return newPopulation }) print("Populationct!)") } catch { print("Error updating population: \(error)") }ViewController.swift
উদ্দেশ্য-সি
FIRDocumentReference *sfReference = [[self.db collectionWithPath:@"cities"] documentWithPath:@"SF"]; [self.db runTransactionWithBlock:^id (FIRTransaction *transaction, NSError **errorPointer) { FIRDocumentSnapshot *sfDocument = [transaction getDocument:sfReference error:errorPointer]; if (*errorPointer != nil) { return nil; } if (![sfDocument.data[@"population"] isKindOfClass:[NSNumber class]]) { *errorPointer = [NSError errorWithDomain:@"AppErrorDomain" code:-1 userInfo:@{ NSLocalizedDescriptionKey: @"Unable to retreive population from snapshot" }]; return nil; } NSInteger population = [sfDocument.data[@"populat>ion"] integerValue]; population++; if (population = 1000000) { *errorPointer = [NSError errorWithDomain:@"AppErrorDomain" code:-2 userInfo:@{ NSLocalizedDescriptionKey: @"Population too big" }]; return @(population); } [transaction updateData:@{ @"population": @(population) } forDocument:sfReference]; return nil; } completion:^(id result, NSError *error) { if (error != nil) { NSLog(@"Transa", error); } else { NSLog(@"Population increased to %@", result); } }];ViewController.m
Kotlin
val sfDocRef = db.collection("cities").document("SF") db.runTransac>tion { transaction - val snapshot = transaction.get(sfDocRef) val newPopulation = snapshot.getDouble("population"<)!! + 1 if (newPopulation = 1000000) { transaction.update(sfDocRef, "population", newPopulation) newPopulation } else { throw FirebaseFirestoreException( "Population too high", FirebaseFirestoreException.Code.ABORTED,> ) } }.addOnSuccessListener { result - Log.d(TAG, "Tran>saction success: $result") }.addOnFailu - Log.w(TAG, "Transaction failure.", e) }DocSnippets.kt
Java
final DocumentReference sfDocRef = db.collection("cities").document("SF"); db.runTransaction(new <Transa>ction.FunctionDouble() { @Override public Double apply(@NonNull Transaction transaction) throws FirebaseFirestoreException { DocumentSnapshot snapshot = transaction.get(sfDocRef); double newPopulation = snapshot.getDouble("population") +< 1; if (newPopulation = 1000000) { transaction.update(sfDocRef, "population", newPopulation); return newPopulation; } else { throw new FirebaseFirestoreException("Population too high", FirebaseFirestoreException.Code.ABORTED); } < } }>).addOnSuccessListener(new OnSuccessListenerDouble() { @Override public void onSuccess(Double result) { Log.d(TAG, "Transaction success: " + result); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception ew(TAG, "Transaction failure.", e); } });DocSnippets.java
Dart
final sfDocRef = db.collection("cities").doc("SF"); db.runTransaction((transaction) { return transaction.get(sfDocRef).then((sfDoc) { final newPopulation = sfDoc.get("population") + 1; transaction.update(sfDocRef, {"population": newPopulation}); return newPopula>tion; }); }).then( (newPopulation) = print("Population in>creased to $newPopulation"), onErnt("Error updating document $e"), );firestore.dart
জাভা
পাইথন
Python
সি++
// This is not yet supported.নোড.জেএস
যান
পিএইচপি
ঐক্য
DocumentReference cityRef = db.Collection("cities").Document("SF"); db.RunTransactio>nAsync(transaction = { return transaction.GetSnapshotAsync(cityRef).C>ontinueWith((task) = { long newPopulation = <task>.Result.GetValuelong("Population") +< 1; if (newPopulation = 1000000) < { > Dictionarystring, o<bject updates >= new Dictionarystring, object { { "Population", newPopulation} }; transaction.Update(cityRef, updates); return true; } else { return false; } }); }>).ContinueWith((transactionResultTask) = { if (transactionResultTask.Result) { Console.WriteLine("Population updated successfully."); } else { Console.WriteLine("Sorry! Population is too big."); } });
সি#
রুবি
লেনদেন ব্যর্থতা
নিম্নলিখিত কারণগুলোর জন্য একটি লেনদেন ব্যর্থ হতে পারে:
- ট্রানজ্যাকশনটিতে রাইট অপারেশনের পরে রিড অপারেশন রয়েছে। যেকোনো রাইট অপারেশনের আগে সর্বদা রিড অপারেশন সম্পাদন করতে হবে।
- ট্রানজ্যাকশনটি এমন একটি ডকুমেন্ট পড়েছে যা ট্রানজ্যাকশনের বাইরে পরিবর্তন করা হয়েছিল। এক্ষেত্রে, ট্রানজ্যাকশনটি স্বয়ংক্রিয়ভাবে পুনরায় চলে। ট্রানজ্যাকশনটি একটি নির্দিষ্ট সংখ্যক বার পুনরায় চেষ্টা করা হয়।
লেনদেনটি ১০ MiB-এর সর্বোচ্চ অনুরোধের আকার অতিক্রম করেছে।
লেনদেনের আকার নির্ভর করে লেনদেন দ্বারা পরিবর্তিত ডকুমেন্ট এবং ইনডেক্স এন্ট্রিগুলোর আকারের উপর। একটি ডিলিট অপারেশনের ক্ষেত্রে, এর মধ্যে অন্তর্ভুক্ত থাকে টার্গেট ডকুমেন্টের আকার এবং অপারেশনটির প্রতিক্রিয়ায় ডিলিট করা ইনডেক্স এন্ট্রিগুলোর আকার।
লেনদেনটি লক ডেডলাইন (২০ সেকেন্ড) অতিক্রম করেছে। কোনো লেনদেন সময়মতো সম্পন্ন হতে না পারলে Cloud Firestore স্বয়ংক্রিয়ভাবে লকগুলো ছেড়ে দেয়।
লেনদেনটি ২৭০-সেকেন্ডের সময়সীমা বা ৬০-সেকেন্ডের নিষ্ক্রিয় মেয়াদোত্তীর্ণের সময় অতিক্রম করে। যদি লেনদেনটির মধ্যে কোনো কার্যকলাপ (পঠন বা লিখন) না ঘটে, তবে এটির সময়সীমা শেষ হয়ে যাবে এবং এটি ব্যর্থ হবে।
একটি ব্যর্থ ট্রানজ্যাকশন একটি ত্রুটি দেখায় এবং ডেটাবেসে কিছু লেখে না। আপনার ট্রানজ্যাকশনটি রোল ব্যাক করার প্রয়োজন নেই; Cloud Firestore এটি স্বয়ংক্রিয়ভাবে করে থাকে।
ব্যাচড লিখেছেন
আপনার অপারেশন সেটে কোনো ডকুমেন্ট পড়ার প্রয়োজন না হলে, আপনি set() , update() , বা delete() অপারেশনের যেকোনো সংমিশ্রণে একাধিক রাইট অপারেশন একটি একক ব্যাচ হিসাবে সম্পাদন করতে পারেন। ব্যাচের প্রতিটি অপারেশন আপনার Cloud Firestore ব্যবহারের ক্ষেত্রে আলাদাভাবে গণনা করা হয়। একটি রাইট ব্যাচ অ্যাটমিকভাবে সম্পন্ন হয় এবং একাধিক ডকুমেন্টে লিখতে পারে। নিম্নলিখিত উদাহরণটি দেখায় কিভাবে একটি রাইট ব্যাচ তৈরি এবং কমিট করতে হয়:
Web
import { writeBatch, doc } from "firebase/firestore"; // Get a new write batch const batch = writeBatch(db); // Set the value of 'NYC' const nycRef = doc(db, "cities", "NYC"); batch.set(nycRef, {name: "New York City"}); // Update the population of 'SF' const sfRef = doc(db, "cities", "SF"); batch.update(sfRef, {"population": 1000000}); // Delete the city 'LA' const la"cities", "LA"); batch.delete(laRef); // Commit the batch await batch.commit();write_batch.js
Web
// Get a new write batch var batch = db.batch(); // Set the value of 'NYC' var nycRef = db.collection("cities").doc("NYC"); batch.set(nycRef, {name: "New York City"}); // Update the population of 'SF' var sfRef = db.collection("cities").doc("SF"); batch.update(sfRef, {"population": 1000000}); // Delete the city 'LA' var laRef = db.collection(&qu>ot;cities").;); batch.delete(laRef); // Commit the batch batch.commit().then(() = { // ... });test.firestore.js
সুইফট
// Get new write batch let batch = db.batch() // Set the value of 'NYC' let nycRef = db.collection("cities").document("NYC") batch.setData([:], forDocument: nycRef) // Update the population of 'SF' let sfRef = db.collection("cities").document("SF") batch.updateData(["population": 1000000 ], forDocument: sfRef) // Delete the city 'LA' let laRef = db.collection("cities").document("LA") batch.deleteDocument(laRef) // Commit the batch do { try await batch.ct;Batch write succeeded.") } catch { print("Error writing batch: \(error)") }ViewController.swift
উদ্দেশ্য-সি
// Get new write batch FIRWriteBatch *batch = [self.db batch]; // Set the value of 'NYC' FIRDocumentReference *nycRef = [[self.db collectionWithPath:@"cities"] documentWithPath:@"NYC"]; [batch setData:@{} forDocument:nycRef]; // Update the population of 'SF' FIRDocumentReference *sfRef = [[self.db collectionWithPath:@"cities"] documentWithPath:@"SF"]; [batch updateData:@{ @"population": @1000000 } forDocument:sfRef]; // Delete the city 'LA' FIRDocumentReference *laRef = [[self.db collectionWithPath:@"cities"] documentWithPath:@"LA"]; [batch deleteDocument:laRef]; // Commit the batch [batch commitWithCompletion:^(NSError * _Nullable error) { if (error != nil) { NSLwriting batch %@", error); } else { NSLog(@"Batch write succeeded."); } }];ViewController.m
Kotlin
val nycRef = db.collection("cities").document("NYC") val sfRef = db.collection("cities").document("SF") val laRef = db.collection("cities").document("LA") // Get a new write> batch and commit all write operations db.runBatch { batch - // Set the value of 'NYC' batch.set(nycRef, City()) // Update the population of 'SF' batch.update(sfRef, "population", 1000000L) city 'LA' batch.delete(laRef) }.addOnCompleteListener { // ... }DocSnippets.kt
Java
// Get a new write batch WriteBatch batch = db.batch(); // Set the value of 'NYC' DocumentReference nycRef = db.collection("cities").document("NYC"); batch.set(nycRef, new City()); // Update the population of 'SF' DocumentReference sfRef = db.collection("cities").document("SF"); batch.update(sfRef, "population", 1000000L); // Delete the city 'LA' DocumentReference laRef = db.collection("cities").document("LA"); batch.d<elet>e(laRef); // Commit the batch batch.commit().addOnComplete<List>ener(new OnCompleteListenerVoid() public void onComplete(@NonNull TaskVoid task) { // ... } });DocSnippets.java
Dart
// Get a new write batch final batch = db.batch(); // Set the value of 'NYC' var nycRef = db.collection("cities").doc("NYC"); batch.set(nycRef, {"name": "New York City"}); // Update the population of 'SF' var sfRef = db.collection("cities").doc("SF"); batch.update(sfRef, {"population": 1000000}); // Delete the city 'LA' var laRef = db.collection("coc("LA"); batch.delete(laRef); // Commit the batch batch.commit().then((_) { // ... });firestore.dart
জাভা
পাইথন
Python
সি++
// Get a new write batch WriteBatch batch = db->batch(); // Set the value of 'NYC' DocumentReference nyc_r>ef = db-Collection("cities").Document("NYC"); batch.Set(nyc_ref, {}); // Update the population of 'SF>' DocumentReference sf_ref = db-Collection("citie{{"population", FieldValue::Integer(1000000)}s").Document("SF"); batch.Update(sf_ref, });> // Delete the city 'LA' DocumentReference la_ref = db-Collection("cities").Document("LA"); ba<tch.>&Delete(la_ref); // Commit the batch batch.Commit().OnCompletion([](<<const Futurevoid future)<< { if (future.error() == Error::kEr<<rorOk) { std::cout &<<quot;Write batch success<<!" std::endl; std::cout "Write batch failure: " future.error_message() std::endl; } });snippets.cpp
নোড.জেএস
যান
পিএইচপি
ঐক্য
WriteBatch batch = db.StartBatch(); // Set the data for NYC DocumentReference nycRef = db.Collection("cities").Document("NY<C"); Dict>ionarystring, object nycD<ata = new Dict>ionarystring, object { { "name", "New York City" } }; batch.Set(nycRef, nycData); // Update the population for SF DocumentReference sfRef = db.Collect<ion("citi>es").Document("<SF"); Dic>tionarystring, object updates = new Dictionarystring, object { { "Population", 1000000} }; batch.Update(sfRef, updates); // Delete LA DocumentReference laRef = db.Collection("cities").Document("LA"); batch.Delete(laRef); // Commit the batch batch.CommitAsync();
সি#
রুবি
ট্রানজ্যাকশনের মতোই, ব্যাচড রাইটও অ্যাটমিক। ট্রানজ্যাকশনের বিপরীতে, ব্যাচড রাইটের ক্ষেত্রে পঠিত ডকুমেন্টগুলো অপরিবর্তিত আছে কিনা তা নিশ্চিত করার প্রয়োজন হয় না, যার ফলে ব্যর্থতার ঘটনা কম ঘটে। এগুলোতে রিট্রাই বা অতিরিক্ত রিট্রাইয়ের কারণে ব্যর্থতার কোনো সম্ভাবনা থাকে না। ব্যবহারকারীর ডিভাইস অফলাইনে থাকলেও ব্যাচড রাইট সম্পাদিত হয়।
শত শত ডকুমেন্ট একসাথে ব্যাচ আকারে লেখার জন্য অনেক ইনডেক্স আপডেটের প্রয়োজন হতে পারে এবং এটি ট্রানজ্যাকশন সাইজের সীমা অতিক্রম করতে পারে। এক্ষেত্রে, প্রতি ব্যাচে ডকুমেন্টের সংখ্যা কমিয়ে দিন। বিপুল সংখ্যক ডকুমেন্ট লেখার জন্য, এর পরিবর্তে বাল্ক রাইটার বা সমান্তরালভাবে পৃথক পৃথক রাইট ব্যবহার করার কথা বিবেচনা করুন।
পারমাণবিক ক্রিয়াকলাপের জন্য ডেটা যাচাইকরণ
মোবাইল/ওয়েব ক্লায়েন্ট লাইব্রেরির জন্য, আপনি Cloud Firestore Security Rules ব্যবহার করে ডেটা ভ্যালিডেট করতে পারেন। আপনি নিশ্চিত করতে পারেন যে সম্পর্কিত ডকুমেন্টগুলো সর্বদা অ্যাটমিকভাবে এবং একটি ট্রানজ্যাকশন বা ব্যাচড রাইটের অংশ হিসেবে আপডেট হয়। এক সেট অপারেশন সম্পন্ন হওয়ার পরে কিন্তু Cloud Firestore অপারেশনগুলো কমিট করার আগে , কোনো ডকুমেন্টের অবস্থা অ্যাক্সেস ও ভ্যালিডেট করতে getAfter() সিকিউরিটি রুল ফাংশনটি ব্যবহার করুন।
উদাহরণস্বরূপ, কল্পনা করুন যে cities উদাহরণের ডাটাবেসে একটি countries কালেকশনও রয়েছে। প্রতিটি country ডকুমেন্টে একটি last_updated ফিল্ড ব্যবহার করা হয়, যা সেই দেশের সাথে সম্পর্কিত কোনো শহর শেষবার কখন আপডেট করা হয়েছিল তার হিসাব রাখে। নিম্নলিখিত নিরাপত্তা নিয়মগুলো অনুযায়ী, একটি city ডকুমেন্ট আপডেট করা হলে, সংশ্লিষ্ট দেশের last_updated ফিল্ডটিও অ্যাটমিকভাবে আপডেট হতে হবে:
service cloud.firestore { match /databases/{database}/documents { // If you update a city doc, you must also // update the related country's last_updated field. match /cities/{city} { allow write: if request.auth != null && getAfter( /databases/$(database)/documents/countries/$(request.resource.data.country) ).data.last_updated == request.time; } match /countries/{country} { allow write: if request.auth != null; } } }
নিরাপত্তা নিয়মের সীমাবদ্ধতা
ট্রানজ্যাকশন বা ব্যাচড রাইটের নিরাপত্তা নিয়মে, ব্যাচের প্রতিটি একক ডকুমেন্ট অপারেশনের জন্য স্বাভাবিক ১০টি কল সীমার পাশাপাশি, সম্পূর্ণ অ্যাটমিক অপারেশনের জন্য ২০টি ডকুমেন্ট অ্যাক্সেস কলের একটি সীমা রয়েছে।
উদাহরণস্বরূপ, একটি চ্যাট অ্যাপ্লিকেশনের জন্য নিম্নলিখিত নিয়মগুলো বিবেচনা করুন:
service cloud.firestore { match /databases/{db}/documents { function prefix() { return /databases/{db}/documents; } match /chatroom/{roomId} { allow read, write: if request.auth != null && roomId in get(/$(prefix())/users/$(request.auth.uid)).data.chats || exists(/$(prefix())/admins/$(request.auth.uid)); } match /users/{userId} { allow read, write: if request.auth != null && request.auth.uid == userId || exists(/$(prefix())/admins/$(request.auth.uid)); } match /admins/{userId} { allow read, write: if request.auth != null && exists(/$(prefix())/admins/$(request.auth.uid)); } } }
নিচের কোড স্নিপেটগুলো কয়েকটি ডেটা অ্যাক্সেস প্যাটার্নের জন্য ব্যবহৃত ডকুমেন্ট অ্যাক্সেস কলের সংখ্যা তুলে ধরেছে:
// 0 document access calls used, because the rules evaluation short-circuits // before the exists() call is invoked. db.collection('user').doc('myuid').get(...); // 1 document access call used. The maximum total allowed for this call // is 10, because it is a single document request. db.collection('chatroom').doc('mygroup').get(...); // Initializing a write batch... var batch = db.batch(); // 2 document access calls used, 10 allowed. var group1Ref = db.collection("chatroom").doc("group1"); batch.set(group1Ref, {msg: "Hello, from Admin!"}); // 1 document access call used, 10 allowed. var newUserRef = db.collection("users").doc("newuser"); batch.update(newUserRef, {"lastSignedIn": new Date()}); // 1 document access call used, 10 allowed. var removedAdminRef = db.collection("admin").doc("otheruser"); batch.delete(removedAdminRef); // The batch used a total of 2 + 1 + 1 = 4 document access calls, out of a total // 20 allowed. batch.commit();
বড় আকারের রাইট ও ব্যাচড রাইটের কারণে সৃষ্ট ল্যাটেন্সি সমস্যা, ওভারল্যাপিং ট্রানজ্যাকশনের দ্বন্দ্বজনিত ত্রুটি এবং অন্যান্য সমস্যা সমাধানের উপায় সম্পর্কে আরও তথ্যের জন্য ট্রাবলশুটিং পেজটি দেখে নিতে পারেন।