How to fetch data and update it from firebase - flutter

I am having trouble trying to fetch data from firebase and updating the values from it.
I have a restaurant name and the number of times it has been picked (user chooses to go to that restaurant to eat). I am trying to retrieve the numPicked and update it by adding one if the user decides to go there again.
Here i am trying to fetch ONE specific document and trying to store the docID and the variables I need to update.
docID = doc.id; docID is return NULL
meaning that the foreach loop isn't even being read.
Future<bool> searchQuery(
{required String restaurantName,
required var userID,
required db}) async {
int addOne = 1; //addes one if it has been picked
//this is not working
try {
Query query2 =
db.where('userId', isEqualTo: FirebaseAuth.instance.currentUser!.uid);
Query query = query2.where('restaurantName', isEqualTo: restaurantName);
await query.get().then((querySnapshot) {
// ignore: avoid_function_literals_in_foreach_calls
querySnapshot.docs.forEach((doc) {
docID = doc.id;
numPicked = doc['numPicked'];
restaurantExist = true;
});
}).catchError((error) {
// print('error querying: #error');
});
} catch (ex) {
// ignore: avoid_print
print(ex);
}
//this is not working
int totalPicked = numPicked + addOne;
//if the restaurant exist then update the numpicked for that specific restaurant
if (restaurantExist) {
try {
var query = db
//.collection('NumRestaurantPicked')
.doc(docID);
await query.update({'numPicked': totalPicked.toString()});
} catch (ex) {}
}
return restaurantExist;
}

The docID and numPicked variables are not defined in the method signature, so they are not accessible outside of the try block. They should be defined as class variables, so they can be accessed from other methods.

Related

How to pass a List or specific looped list to firebase doc in flutter

I am trying to achieve a task in which I have a List<dynamic>and its giving me multiple values on its indexes e.g. ['Me','Admin', so on....] something like this.
I cannot pass the List directly to Document ID it gives index error and I don't if it will still give error or not If the List give data in string List<String>
I want to loop around the indexes of this list and pass it to Firebase collection's document id to get multiple data's of the users. For example on list's index 0 there's Me coming for myself and on index 1 there's Admin coming. Both have their respective data stored in Firestore collection with their own document id's Me and Admin. I want it to be checked on the runtime the app will check if its Me or Admin or Some other index value
Here's my code of the list and the firestore I'm trying to achieve.
List<dynamic> clientcodes = [];
void getclientcodes() async {
final clientcode = await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser!.email)
.get()
.then((clientcode) {
return clientcode.data()!["clientcode"];
});
setState(() {
if (clientcode != null) {
clientcodes = clientcode;
} else if (clientcode == null) {
setState(() {
const SpinKitSpinningLines(size: 100, color: Color(0xFF25315B));
});
}
});
}
Firestore:
Future getdatastatus() async {
DocumentSnapshot result = await FirebaseFirestore.instance
.collection("Statements")
// .doc("If I hardcode it the value of index 0 or 1 it works fine")
.doc(portfolionames.toString()) // This is area of issue
.get();
if (result.exists) {
print("Yes");
} else {
print("No");
}
}
You can insert getdatastatus() inside a loop, and let it get the index automatically by comparing it with any value you want it, see this:
Future getdatastatus() async {
for (var item in clientcodes) {
String docId = item.id;
if (docId == 'X' || docId == 'Y') {
DocumentSnapshot result = await FirebaseFirestore.instance
.collection("Statements")
.doc(docId)
.get();
if (result.exists) {
print("Yes");
} else {
print("No");
}
}
}
}
Hope that work with you!!
Update
In the first section of your code, I think there is a problem..
You can create the list out of the firestore streaming, then add the coming data to the list of model, after that you can loop it to take the value you want.
Class Database{
List<TestModel> clientcodes = [];
getclientcodes() {
return FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser!.email)
.snapshots()
.listen((event) {
clientcodes.add(TestModel.fromMap(event));
setState(() {
if (clientcode != null) {
clientcodes = clientcode;
} else if (clientcode == null) {
setState(() {
const SpinKitSpinningLines(size: 100, color: Color(0xFF25315B));
});
}
});
});
}
}
class TestModel {
late String name;
late String description;
TestModel({
required this.name,
required this.description,
});
TestModel.fromMap(DocumentSnapshot data) {
name = data['name'];
description = data['description'];
}
}

How to use Array contains in the same array fields in firebase for flutter

I have a chat collection.
each document has an array with two user id's.
my goal is to get the chat that has both user sys id's
I tried running the following but I got an error because we cant use two 'arrayContains' in one query.
Is there any way to perform such query?
here is an image of the data structure
Future getChat({required List userIdsArr}) async {
var docId = '';
userIdsArr.sort((a, b) {
return a.compareTo(b);
});
var filter1 = userIdsArr[0];
var filter2 = userIdsArr[1];
await chat
.where(userIdsArrayColumn, arrayContains: userIdsArr[0])
.where(userIdsArrayColumn, arrayContains: userIdsArr[1])
.get()
.then((value) {
value.docs.forEach((element) {
docId = element.id;
});
});
return docId;
}
the goal is to get the chat that pertains to the users being passed in userIdsArr
this seems to work, is there a better way of doing this?
Future getChat({required List userIdsArr}) async {
var docId = '';
userIdsArr.sort((a, b) {
return a.compareTo(b);
});
await chat
.where(userIdsArrayColumn, arrayContains: userIdsArr[0])
// .where(userIdsArrayColumn, arrayContains: userIdsArr[1])
.get()
.then((value) {
value.docs.forEach((element) {
if (element[userIdsArrayColumn].contains(userIdsArr[1])) {
log('match found!');
docId = element.id;
}
});
});
return docId;
}
A query can only contain a single array-contains query.
To allow your query, you'll want to add an additional field to the document where you keep the pair of UIDs in a predictable (e.g. alphabetical) order. With such a field you can then use a query such as:
where("concatenated_uids", isEqualTo: userIdsArr[0]+"_"+ userIdsArr[1])

Is there a way to check the value of a specific field in a document?

I'm trying to compare the text inputted by user to my firestore collection.
But when I tried this code:
docSnapshot.data()!.containsValue(currentStudPass);
where currentStudPass is a String that contains the User ID which is 184-0055
It works but it's trying to search for all the fields value that the user has,
for example I tried "Test Section" as a password, it will return true.
I want to exclude all fields except the password: or just use containsValue for password: field. But I don't have any idea how to do that I'm new to Flutter.
I tried:
docSnapshot.data()!.containsValue('password: $currentStudPass');
var docSnapshot = await collection.doc("$currentStudId/password").get();
But it doesn't work.
Here's my firestore db.
static Future<bool> checkPass(String passArg) async {
// method to check if the users password is correct
var collection = FirebaseFirestore.instance.collection('users');
var docSnapshot = await collection.doc("$currentStudId").get();
try {
passCheck =
docSnapshot.data()!.containsValue(currentStudPass);
return passCheck;
} catch (e) {
// If any error
return false;
}
try this if this works.
static Future<bool> checkPass({String? id, String? passArg}) async {
final collection = FirebaseFirestore.instance.collection('users');
final docs = await collection.doc(id!).get();
final Map<String,dynamic> map = docs.data() as Map<String,dynamic>;
// you can direct it since the result from contains is bool
return map['password'].toString().contains(passArg!);
// Edit : you can use operator == to know exact input
// return map['password'] == passArg!;
}

Getting document from Firestore to pun inside a Custom User profile but it returns null. Dart/Flutter

Hi there I'm having some trouble to retrieve data from Firestore;
I created a class User for getting all the information for my app.
User Class:
class User {
String id;
String displayName;
String email;
String pictureURL;
String gender;
DateTime dateOfBirth;
User(fbauth.User user) {
id = user.uid;
displayName = user.displayName;
email = user.email;
pictureURL = user.photoURL;
// setting info
DocumentSnapshot resl = FirestoreUtil.read("AdditionalUserInfo", user.uid);
gender = resl.data()['gender'];
dateOfBirth = (resl.data()['date of birth'] as Timestamp).toDate();
}
FirestoreUtils class:
class FirestoreUtil {
static DocumentSnapshot read(String collection, String document) {
FirebaseFirestore.instance
.collection(collection)
.doc(document)
.get()
.then((DocumentSnapshot snapshot) {
if(snapshot.exists){
return snapshot;
}else{
print("no data found");
}
});
}
}
After I return the snapshot, it gets null. But if I do this it prints out the correct values:
class FirestoreUtil {
static DocumentSnapshot read(String collection, String document) {
FirebaseFirestore.instance
.collection(collection)
.doc(document)
.get()
.then((DocumentSnapshot snapshot) {
if(snapshot.exists){
print(snapshot.data);
}else{
print("no data found");
}
});
}
}
I tried literally everything but I couldn't figure out. Could someone help? I cannot imagine that is that hard to retrieve data inside a class.
It's probably Future(async/await) problem. You are returning value inside Future, you can get this value inside another then() etc.
class FirestoreUtil {
static DocumentSnapshot read(String collection, String document) async {
// You can directly return it too without assigning it to result variable
var result = await FirebaseFirestore.instance
.collection(collection)
.doc(document)
.get();
return result;
}
}
There is data() method for DocumentSnapshot, you can use result.data() and check if it's null, isEmpty etc.
I wrote this function with async/await but if you need Future and didn't want to wait operation to be finished, you can directly return
FirebaseFirestore.instance.collection(collection).doc(document).get();
and you can use then() after you get the Future.

FIrestore Query Document in Collection Using Single Field/Attribute in Flutter

I am trying to fetch the role of the currently authenticated user stored in users collection. What I am trying to achieve is at login time, query the user role by traversing fetching the user's document in the collection and sifting through the fields or checking all documents and returning the field role as a string.
Collection and document snapshot(excuse the terminology):
All documents in users collection have same fields for now.
Please how do I go about writing this type of query in flutter? I have tried using AuthResult in my service and FirebaseAuth to get current user(but no way to access the fields in the document).
Thanks.
String role;
getUserRoleWithFuture() async {
String currID = await _authService.getCurrentUID();
String mRole;
Firestore.instance.collection(USERS_REF).document(currID).get().then((doc) {
mRole = doc.data['role'];
print(mRole);
});
return mRole;
}
Future<String> getUserRoleWithStream() async {
String currID = await _authService.getCurrentUID();
String sRole;
Firestore.instance
.collection(USERS_REF)
.document(currID)
.snapshots()
.listen((DocumentSnapshot ds) {
if (ds.exists) {
sRole = ds.data['role'];
print('with stream:\t$sRole');
}
});
return sRole;
}
In the method getUserRoleWithStream() I am trying to retrieve the value printed out like role = getUserRoleWithStream() but instead get this in console a value of type Future<String> can't be assigned to a variable of type string.
How do I get this value using either the stream (cos it constantly observes the collection) or using the other method and use it in my widget?
Thanks again.
This is the working solution, in case anyone else runs into this. I appreciate the effort made into helping me understand the issue but here's the answer:
String role;
getUserRoleWithFuture() async {
String currID = await _authService.getCurrentUID();
String mRole;
Firestore.instance.collection(USERS_REF).document(currID).get().then((doc) {
mRole = doc.data['role'];
print(mRole);
});
return mRole;
}
Future<String> getUserRoleWithStream() async {
String currID = await _authService.getCurrentUID();
String sRole;
Firestore.instance
.collection(USERS_REF)
.document(currID)
.snapshots()
.listen((DocumentSnapshot ds) {
if (ds.exists) {
sRole = ds.data['role'];
print('with stream:\t$sRole');
}
});
return sRole;
}
Well first off, I assume the AuthResult.user.uid and your user's collection user's id is same. So that once you have the user from AuthResult, you can query your firestore collection to get the user's role as follows.
Future<String> getUserRole(String uid) async {
DocumentSnapshot ds = await Firestore.instance.collection('users').document(uid).get();
return ds.data['role'];
}