I want to get document id from my firestore - firebase

I can't get document id from firestore check out the screenshot, you will understand better.
Future updateUserData(String name, String address, String description,
String image, String rating) async {
return await collectionReference.document(uid).setData({
'name': name,
'address': address,
'description': description,
'image': image,
'rating': rating,
'berberid' : ######, // what should I write here
});
}
Instead of null I want to pass that id
Couple of method I already tried
This is returning null
String docid() {
String id;
collectionReference.getDocuments().then((value) => {
value.documents.forEach((element) {
id = element.documentID;
}),
});
return id;
}
This returns the name of collection, such as berbers
documentReference.documentID

Data is loaded from Firebase asynchronously. That means that in this code:
String id;
collectionReference.getDocuments().then((value) =>{
value.documents.forEach((element) {
id= element.documentID;
}),
});
return id;
}
By the time the return id statement executes, the id= element.documentID hasn't run yet. You can most easily check this for yourself by putting breakpoints on these lines and running the code in the debugger, or by adding some log statements:
print("Before getDocuments()");
collectionReference.getDocuments().then((value) =>{
print("Got documents");
});
print("Aftter getDocuments()");
When you run this code, it prints:
Before getDocuments()
After getDocuments()
Got documents
This is likely not what you expected, but does explain why you get null from the function: the data hasn't loaded yet by the time your function exits.
This is completely normal when dealing with asynchronous operations, which is pretty much any modern web/cloud API. So you'll have to deal with it in your code.
The quickest way to do that is to move the code that needs the data into the then() callback that gets the data. So instead of return id you actually put the code that uses the id into the method:
collectionReference.getDocuments().then((value) =>{
String id;
value.documents.forEach((element) {
id= element.documentID;
}),
print(id); // use the id here
});
This could also be a call to your updateUserData function.
Alternatively, you can use async / await and return a Future from your function:
Future<string> getDocumentId() async {
String id;
var value = await collectionReference.getDocuments();
value.documents.forEach((element) {
id= element.documentID;
}),
return id;
}
To call this function you then do:
getDocumentId().then((id) =>{
print(id); // use id here
})
Or you can use another await and do:
var id = await getDocumentId()
print(id);

Here's what I think you should do, you add the documentID to barberid when you create the document instead of updating it which is weird how the user know ?. Here's how you do it:
await Firestore.instance.collection("your collection name").add({
'name': name,
'address': address,
'description': description,
'image': image,
'rating': rating,
}).then((value) => Firestore.instance
.document(value.path)
.updateData({"barberid": value.documentID}));
value there is DocumentReference that's how you get the documentID and then you can update it with Firestore.instance.document("document path") fill the document path with value.path, and update the barberid with documentID should work just fine.

Related

Running Async Code in factory Function in Flutter / Dart

I have this function using factory, (which to be honest I'm not sure why is needed, I just got it from a Tutorial, but is working the rest of the code).
This is the Function in question:
factory Listing.fromJason(Map<String, dynamic> data, String id) {
List<String> images = [];
data['photos'].forEach((photo) {
images.add(photo);
});
return Listing(
id: id,
photos: images,
price: double.parse(data['price'].toString()),
status: data['status'],
street: data['street'],
street2: data['street2'],
city: data['city'],
state: data['state'],
zipCode: int.parse(data['zipCode'].toString()),
bedRooms: data['bedRooms'],
bathRooms: data['bathRooms'],
lotSize: data['lotSize'],
schoolDistric: data['schoolDistric'],
taxes: double.parse(data['taxes'].toString()),
homeFeatures: data['homeFeatures'],
floorPlans: data['floorPlans'],
propertySurvey: data['propertySurvey'],
yearBuilt: data['yearBuilt'],
listingAgentName: data['listingAgentName'],
listingAgentEmail: data['listingAgentEmail'],
listingAgentPhone: data['listingAgentPhone'],
dayStore: DateTime.parse(data['dayStore'].toDate().toString()),
downPayment: data['downPayment'],
county: data['county'],
url: data['url'],
listingType: data['listingType'],
name: data['name'],
username: data['username'],
email: data['email'],
imageUrl: data['image_url'],
//isFavorite: favStat,
);
}
The Problem that I'm having is that I need to call inside of it this function to evaluate the Favorite Status:
Future<bool> isItFav(docId) async {
final user = FirebaseAuth.instance.currentUser;
final uid = user.uid;
DocumentSnapshot favoriteSnapshot = await FirebaseFirestore.instance
.doc('userfavorites/$uid/favorites/$docId')
.get();
bool result = favoriteSnapshot.exists;
return result;
}
The problem is that inside that function the one with the factory doesn't allow me to leave it as async or to put an await.
And I need to evaluate with the value of id (which I get as a parameter on top) if the document for that collection (the one on the isItFav function) exists and with that bool add it to the Listing object that I'm returning.
Any Ideas on what I can do.
Just use a static method instead of a named factory constructor. A factory constructor offers no significant advantages in this case.

Firebase duplicates presumably because of offline behavior

I have an app (Flutter / Firebase) where people save their predictions for soccer matches.
The way it works is: every person has a document per round of soccer matches.
So when saving a prediction, I check if there is a document for that person for that round, if it does, I write into it, if it doesn't I create a new document.
It was working fine until the amount of users and their circumstances increased. Now, I'm getting a few duplicates and I'm guessing it's because the person saving picks has no internet connection so it doesn't find a document and tries to write a new one.
What would be the best approach to fix this?
Designing a specific reference path for the documents?
Checking for internet connection before attempting any writes?
Or something else?
Future<String> saveToFirebase() async {
return await Firestore.instance.collection('picks')
.add(this.toJson())
.then((value) => Future.value(value.documentID))
.catchError((onError) => Future.error(onError));
}
Future<DocumentReference> picksDocumentReferenceFor(User user, String round, String groupId, String leagueId, { bool create = false, String roundName, String seasonId }) async {
String path = 'picks/';
return Firestore.instance
.collection('picks')
.where('groupId', isEqualTo: groupId)
.where('userId', isEqualTo: user.id)
.where('round', isEqualTo: round).getDocuments()
.then((value) async {
String docPath;
if (value.documents.isEmpty) {
//No document found.. need to create it.
if (create) {
await PicksDocument().saveToFirebase()
.then((documentId) {
docPath = path + documentId;
});
}
} else {
docPath = path + value.documents.first.documentID;
}
print(docPath);
DocumentReference ref;
if (docPath != null) ref = Firestore.instance.document(docPath);
return Future.value(ref);
});
}

How to get a field value from a Document in Firestore?

So, I have learned how to create and update documents in a firebase firestore cloud, however I am having trouble reading data. Attached is my code for finding the value of the 'photourl' field:
String photoy;
Firestore.instance.collection('userdata').document('sepDGexTRuRkpx1WQYylDDmUI573')
.get().then((DocumentSnapshot ds){
photoy=ds.data['photourl'];
});
setState(() {
photourldisplay=photoy;
});
However, upon running my program, the photourldisplay value seems to not have changed and remains null upon running. This means that something is askew with my code that retrieves this "photourl" field. Can someone help me retrieve a field in a firebase document?
photoy does not contain the value you expect because Firestore queries are asynchronous. The get() returns immediately, and the callback is invoked some time later, after the query completes. There is no guarantee how long a query might take. If you want to pass the value of photoy to something else, you will have to wait until the callback completes by making use of it only within that callback.
Firestore.instance.collection('userdata').document('sepDGexTRuRkpx1WQYylDDmUI573')
.get().then((DocumentSnapshot ds){
photoy=ds.data['photourl'];
setState(() {
photourldisplay=photoy;
});
});
Your code is good you just have to await for the result:
void yourVoid () async {
String photoy;
await Firestore.instance.collection('userdata').document('sepDGexTRuRkpx1WQYylDDmUI573')
.get().then((DocumentSnapshot ds){
photoy=ds.data['photourl'];
});
setState(() {
photourldisplay=photoy;
});
}
EDIT:
as #Doug Stevenson said, there is two propers solutions:
void yourVoid () async {
DocumentSnapshot ds = await Firestore.instance.collection('userdata').document('sepDGexTRuRkpx1WQYylDDmUI573')
.get();
String photoy = ds.data['photourl'];
setState(() {
photourldisplay=photoy;
});
}
and:
Firestore.instance.collection('userdata').document('sepDGexTRuRkpx1WQYylDDmUI573')
.get().then((DocumentSnapshot ds){
photoy=ds.data['photourl'];
setState(() {
photourldisplay=photoy;
});
});

How do I get the surrounding data related to my userId using flutter and firebase

While using flutter I am able to successfully get the UserId, however I want to be able get more user data (using the UserId)
Surrounding Information:
With the userId how would I go about printing the users; name bio, membership... etc?
Since you are using Realtime Database, then to get the other data, you can do the following:
db = FirebaseDatabase.instance.reference().child("Users");
db.once().then((DataSnapshot snapshot){
Map<dynamic, dynamic> values = snapshot.value;
values.forEach((key,values) {
print(values);
print(values["name"]);
});
});
First add a reference to node Users then use the forEach method to iterate inside the retrieved Map and retrieve the other values.
Try like this :
Future<dynamic> getWeightinKeg() async {
final DocumentReference document = Firestore.instance.collection('you_collection_name').document(user_id);
await document.get().then<dynamic>(( DocumentSnapshot snapshot) async {
final dynamic data = snapshot.data;
print(data['name'].toString())
//Do whatever you want to do with data here.
});
}
getUsers() async {
//here fbPath is reference to your users path
fbPath.once().then((user){
if(user.value !=null){
Map.from(user.value).forEach((k,v){
//here users is List<Map>
setState((){
users.add(v);
});
}
}
});
}
//Or
getUsers() async {
//here fbPath is reference to your users path
//and userListener is StreamSubscription
userListener = fbPath.onChildAdded.listen((user){
//here users is List<Map>
setState((){
users.add(Map.from(user.snapshot.value));
});
});
}
//and cancel in dispose method by calling
userListener.cancel();

A simple Query in flutter/firebase database

I try to experience Firebase Live database with flutter.
I just would like to get a value in the datasnapshot of the firebase response.
My Firebase
My Code
static Future<User> getUser(String userKey) async {
Completer<User> completer = new Completer<User>();
String accountKey = await Preferences.getAccountKey();
FirebaseDatabase.instance
.reference()
.child("accounts")
.child(accountKey)
.child("users")
.childOrderBy("Group_id")
.equals("54")
.once()
.then((DataSnapshot snapshot) {
var user = new User.fromSnapShot(snapshot.key, snapshot.value);
completer.complete(user);
});
return completer.future;
}
}
class User {
final String key;
String firstName;
Todo.fromJson(this.key, Map data) {
firstname= data['Firstname'];
if (firstname== null) {
firstname= '';
}
}
}
I got Null value for firstname.
I guess I should navigate to the child of snapshot.value. But impossible to manage with foreach, or Map(), ...
Kind regards, Jerome
You are querying with a query and the documentation for Queries (here in JavaScript, but it is valid for all languages), says that "even when there is only a single match for the query, the snapshot is still a list; it just contains a single item. To access the item, you need to loop over the result."
I don't know exactly how you should loop, in Flutter/Dart, over the children of the snapshot but you should do something like the following (in JavaScript):
snapshot.forEach(function(childSnapshot) {
var childKey = childSnapshot.key;
var childData = childSnapshot.val();
// ...
});
and assuming that your query returns only one record ("one single match"), use the child snapshot when you do
var user = new User.fromSnapShot(childSnapshot.key, childSnapshot.value);
This will give you Users in reusable dialog. There might be slight disservice to yourself if you don't use stream and stream-builders, the solution below is a one time fetch of the users' collection on FirebaseDB.
class User {
String firstName, groupID, lastName, pictureURL, userID;
User({this.firstName, this.groupID, this.lastName, this.pictureURL, this.userID});
factory User.fromJSON(Map<dynamic, dynamic> user) => User(firstName: user["Firstname"], groupID: user["Group_id"], lastName: user["Lastname"], pictureURL: user["Picturelink"], userID: user["User_id"]);
}
Future<List<User>> users = Firestore.instance.collection("users").snapshots().asyncMap((users) {
return users.documents.map((user) => User.fromJSON(user.data)).toList();
}).single;

Resources