How to know whether actual current value is null in Firebase Realtime DB Transactions? - firebase

A firebase transaction handler should be able to handle null values, as well as it can be called multiple times. What happens if it is called on a location with a null value. (If there is no existing data) Is there a way to know it from the proceeding promise. How about following code?
let isNull = false;
db.ref('/entry').transaction( currentValue => {
if(!currentValue) {
isNull = true;
// Do the updates
} else {
// Do the update
}
return currentValue;
}).then(() => {
console.log("IsNull", isNull);
})

This example is to check whether a particular user Id is under a node
Use something on the lines of:
//Add this before OnCreate while declaring all variables
FirebaseUser firebaseUserId = FirebaseAuth.getInstance().getCurrentUser();
yourDatabaseSource.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
final String thisFirebaseUser = firebaseUserId.getUid();
if (dataSnapshot.hasChild(thisFirebaseUser)) {
//check your condition
} else {
//do something
}
}
Hope this helps.

Related

How to sequentially call the Getx controllers

My Task is :
I have an list of orders in firebase in users collection ,
I want to get information of those orders which is in orders collection,
And moment a list of order is updated in the firebase users collection.
The orders list should be automatically updated to get the latest information from the orders collection.
But for that i have to wait until list of orders is fetched from the users collection and only then i can query from orders collection about those orders..
I am stuck here,
And i want to actually understand Getx's bindStream , ever(), and observable variables,and Obx() is used in widget , But what if it is normal variable and i want to listen to it's changes ,how to do that, because Obx() can be only used while you use Widget
So far my code:
controllers.dart
UtilityController utilityController = UtilityController.instance;
CartController cartController = CartController.instance;
OrderController orderController = OrderController.instance;
UserModel.dart
class UserModel {
String? uid;
String? email;
String? name;
bool? isAdmin;
String? password;
List<CartItemModel>? cart;
String? token;
List<String>? orders;
UserModel({this.uid, this.email, this.name, this.isAdmin, this.password, this.cart, this.token, this.orders});
UserModel.fromSnapshot(DocumentSnapshot snapshot) {
uid = snapshot.id;
name = snapshot['name'];
token = snapshot['token'];
cart = _convertCartItems(snapshot['cart'] ?? []);
orders = new List<String>.from(snapshot['orders']);
}
List<CartItemModel> _convertCartItems(List cartFomDb) {
List<CartItemModel> _result = [];
if (cartFomDb.length > 0) {
cartFomDb.forEach((element) {
_result.add(CartItemModel.fromMap(element));
});
}
return _result;
}
}
UtilityController.dart
class UtilityController extends GetxController {
static UtilityController instance = Get.find();
Rx<UserModel> userModel = UserModel().obs;
#override
void onReady() {
super.onReady();
getUserType();
userModel.bindStream(listenToUser());
}
Stream<UserModel> listenToUser() {
return FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser?.uid)
.snapshots()
.map((snapshot) => UserModel.fromSnapshot(snapshot));
}
OrderController.dart
class OrderController extends GetxController {
static OrderController instance = Get.find();
RxList<OrderModel> orders = RxList<OrderModel>([]);
#override
void onReady() {
super.onReady();
orders.bindStream(getAllOrders());
ever(utilityController.userModel, function); --> I am using this , but i know this is not the correct way
}
function(UserModel userModel) {
getAllOrders();
}
Stream<List<OrderModel>> getAllOrders() {
return FirebaseFirestore.instance
.collection("orders")
.where(FieldPath.documentId, whereIn: utilityController.userModel.value.orders)
.snapshots()
.map((query) => query.docs.map((item) => OrderModel.fromMap(item.data(), item.id)).toList());
}
}
The utilityController.userModel.value.orders is null !!! it's not yet loaded, so all the orders are fetched :(
And even if the orders are changed... But new orders are not fetched from the orders collection
How to get over this?
Consider using like this.
class OrderController extends GetxController {
static OrderController instance = Get.find();
final isLoading = true.obs;
final isDone = false.obs;
var orders = OrderModel([]).obs;
#override
void onInit() async {
await listenForOrders();
super.onInit();
}
Future listenForOrders() async {
isLoading.value = true;
isDone.value = false;
Stream<QuerySnapshot> _userOrders;
_userOrders = getAllOrders();
_userOrders.listen((QuerySnapshot query) {
if (query.docs.isNotEmpty) {
query.docs.forEach((element) {
orders.addIf(!orders.contains(element), OrderModel.fromDocumentSnapshot(element));
});
} else {
isDone.value = true;
}
isLoading.value = false;
});
}
Stream<QuerySnapshot> getAllOrders() {
return FirebaseFirestore.instance
.collection("orders")
.where(FieldPath.documentId, whereIn: utilityController.userModel.value.orders)
.snapshots();
}
}
The best approach is to use the worker functions provided by getx controller like:
ever - is called every time the Rx variable emits a new value.
everAll - Much like ever , but it takes a List of Rx values Called every time its variable is changed. That's it.
once - is called only the first time the variable has been changed.

How to implement listner for redis stream by using CSRedis XRead

My implementation:
public async void ListenRedisTask()
{
while (!Token.IsCancellationRequested)
{
var lastHandledElement = redisComsumer.WaitToGetNewElement();
if (lastHandledElement != null)
{
await channelProducer.Write(ParseResult(lastHandledElement));
}
}
}
public Dictionary<string, string>? WaitToGetNewElement()
{
var result = client.XRead(1, expiryTime, new (string key, string id)[] { new(streamName, "$") });
if (result != null)
{
return parse(result[0]);
}
return null;
}
In redis stream i have correct data like: insert,delete,insert,delete...
But in channel for storage current hadled item i have data like: delete, delete, delete, insert, delete..
It's wrong!
I think my error connected with using xread, maybe when xread method is called next invoke of this method ignore interstitial data from redis stream.

Flutter + Firebase: How to set state on bool value in documents

I am trying to set the value of a variable based on the return value of a field (bool) in Firestore.
So far, this is what I have come up with;
First I call the method here;
#override
void initState() {
super.initState();
getAdventureStatus();
}
And this is the method.
Future getAdventureStatus() async {
Firestore.instance
.collection('adventures')
.document(widget.currentUser.id)
.collection('user_adventures')
.where('adventure_active', isEqualTo: 'false');
setState(() {
adventureActive = true;
print('${adventureActive.toString()}');
});}
What am I doing wrong and what is the most pragmatic way of doing this?
I think you just remove the set state call and set the bool to true direct.
Future getAdventureStatus() async {
Firebase.instance.document()
...
adventureActive = true;
}

How can I await a variable

Is it possible to use a Future to await a change of value of a simple variable in Dart?
In my case, I have a singleton method that, upon the first call, creates and opens a database. This method is being called from multiple places in my app, and I need a way for the second, third, etc. calls to wait until the first call has created and opened the database.
class DB{
static Database _db;
static Future<Database> instance() async {
if( _db == null ){
print('Creating/opening database');
_db = await createOrOpenDatabase();
}
return _db;
}
}
// Somewhere in the app
await DB.instance().doSomething();
// Meanwhile, somewhere else in the app
await DB.instance().doSomethingElse();
This results in
Creating/opening database
Creating/opening database
One way to solve this would be to add some variable that indicates that the database is currently being created and/or opened:
class DB{
static Database _db;
static bool _openingDb;
static Database instance() async {
if( _openingDb )
// Wait until _openingDb becomes false
if( _db == null ){
_openingDb = true;
print('Creating/opening database');
_db = await createOrOpenDatabase();
_openingDb = false;
}
return _db;
}
}
But just how do I wait for the value of _openingDb to change? It seems like I'm missing something obvious here...
I figured out that I can use a Completer to accomplish what I wanted.
class DB {
static Database _db;
static Completer _dbOpenCompleter;
static Future<Database> instance() async {
if( _dbOpenCompleter != null && !_dbOpenCompleter.isCompleted ) {
print('Awaiting database creation');
await _dbOpenCompleter.future;
}
if( _db == null ) {
_dbOpenCompleter = Completer();
try {
print('Creating/opening database');
_db = await openOrCreateDatabase();
}
finally{
_dbOpenCompleter.complete();
}
}
return _db;
}
}
Now the same calls as in the original question result in the following output:
Creating/opening database
Awaiting database creation

Dart Component: How to return result of asynchronous callback?

Hey there I am quite new to Dart Futures and I have the following situation.
Whenever a user types a letter in the UI the addressChanged() method in my ui_component is called. This method calls the method getProposals() in my maps componenet which does an asynchronous request to the google maps API. As soon as the results are here I want to return them to the UI Component which is going to populate the propasals dropdown in the UI.
I am stuck with the last step: How (and whats the best way) to return the results of an asynchronous callback function to a parent component (while keeping an reusable maps component?).
This is what I have tried:
1) UI_Component:
// I get called if a user typed a new letter
Future addressChanged(dynamic event) async {
String id = event.target.id;
String address = event.target.value;
if(id=="pickup") {
this.pickup = address;
} else if(id=="destination") {
this.destination = address;
}
// this is where I call the subcomponent and want to get the address propasals
String proposals = await googleMap.getProposals(address,id);
print(proposals);
populateProposalDropdown();
}
2) Google Map component:
Future getProposals(String address,String id) async {
await _getProposals(address,id);
}
Future _getProposals(String address,String id) async {
if(address != "") {
autocompleteService.getPlacePredictions(
new AutocompletionRequest()
..input = address
,
(predictions,status) {
List<String> result = [];
if(status == PlacesServiceStatus.OK) {
predictions.forEach(
(AutocompletePrediction prediction) =>
result.add(prediction.description)
);
}
// HERE is the problem: How do I return this result from the callback as a result of the getProposals method?
return result;
}
);
}
}
This method doesn't return any data
Future getProposals(String address,String id) async {
await _getProposals(address,id);
}
Change it to
Future getProposals(String address,String id) {
return _getProposals(address,id);
}
This would also work, but here async and await is redunant
Future getProposals(String address,String id) async {
return await _getProposals(address,id);
}
For _getProposals you can use a Completer
Future _getProposals(String address,String id) async {
if(address != "") {
Completer completer = new Completer();
autocompleteService.getPlacePredictions(
new AutocompletionRequest()
..input = address
,
(predictions,status) {
List<String> result = [];
if(status == PlacesServiceStatus.OK) {
predictions.forEach(
(AutocompletePrediction prediction) =>
result.add(prediction.description)
);
}
// HERE is the problem: How do I return this result from the callback as a result of the getProposals method?
completer.complete(result);
}
);
return completer.future;
}
return null;
}

Resources