I have a list of documents which all hold a coordinate as a value. How can I get all the coordinate and write them into a list. On firebase they are stored as GeoPoints. When I try to get the values from fire base I just get the following.
[Instance of 'GeoPoint', Instance of 'GeoPoint', Instance of 'GeoPoint', ..., Instance of 'GeoPoint', Instance of 'GeoPoint']
Writing to firebase (works)
_markerClick(lat, long) {
FirebaseFirestore.instance
.collection("users")
.doc(user!.uid)
.collection('userLocations')
.add({'coords': GeoPoint(lat, long)});
}
Reading from firebase
Future showMarkers() async {
QuerySnapshot querySnapshot = await FirebaseFirestore.instance
.collection('users')
.doc(user!.uid)
.collection('userLocations')
.get();
final allData = querySnapshot.docs.map((doc) => doc.get('coords'));
print(allData);
}
That seems correct to me: each field is an instance of the GeoPoint class. If you want to get the actual latitude and longitude from the field, use the properties of that object.
querySnapshot.docs.map((doc) => "[${doc.get('coords').latitude}, ${doc.get('coords').longitude}]")
You can try this way too.
const allCoords = [];
await FirebaseFirestore.instance
.collection('users')
.doc(user!.uid)
.collection('userLocations')
.get()
.then((docs) => {
docs.forEach((doc) => {
allCoords.push({
coords: doc.get('coords'),
});
});
});
print(allCoords);
Related
I have a function to retrieve data from firebase as follows,
getTrips() async {
var data = await FirebaseFirestore.instance
.collection('trips')
.orderBy('date')
.where('date', isGreaterThan: DateTime.now())
// .where('date', isGreaterThan: DateTime.parse(widget.searchTrip.date))
.get();
setState(() {
_allTrips = data.docs;
});
return data.docs;
}
I want to iterate the List _allTrips or data.docs and get sum of values in the field 'seats' which is int values on the collection being retrieved by abpve code. How can I achieve this?
add a .then() after the .get() and do the following:
var data = await FirebaseFirestore.instance
.collection('trips')
.orderBy('date')
.where('date', isGreaterThan: DateTime.now())
// .where('date', isGreaterThan: DateTime.parse(widget.searchTrip.date))
.get()
.then((snapshot){
_allTrips = snapshot.docs;
_allTrips.forEach((element)=> totalNumber+=element.data()['seats'])
};
I am creating like system and i want to get likeCount from firebase which i created.
It's collecting it but returns null,
here is my code:
String? getLikecount(tresc) {
String? likeCount;
FirebaseFirestore.instance
.collection('Posty')
.where('Tresc', isEqualTo: tresc)
.get()
.then((value) => value.docs.forEach((element) async {
var id = element.id;
final value = await FirebaseFirestore.instance.collection('Posty').doc(id).get();
likeCount = value.data()!['likeCount'].toString();
print(likeCount);
}));
print(likeCount);
return likeCount;
}
and here is console output:
Data is loaded from Firestore (and most modern cloud APIs) asynchronously, because it may needs to come from the network and we can't block your code (and your users) while waiting for it.
If we change the print statements a bit, and format the code, it'll be much easier to see what's going on:
String? getLikecount(tresc) {
String? likeCount;
FirebaseFirestore.instance
.collection('Posty')
.where('Tresc', isEqualTo: tresc)
.get()
.then((value) => value.docs.forEach((element) async {
var id = element.id;
final value = await FirebaseFirestore.instance
.collection('Posty')
.doc(id)
.get();
likeCount = value.data()!['likeCount'].toString();
print('In then: $likeCount');
}));
print('After then: $likeCount');
return likeCount;
}
If you run this, you'll see it outputs:
After then: null
In then: 0
This is probably not what you expected, but it explains perfectly why you don't get a result. By the time your return likeCount runs, the likeCount = value.data()!['likeCount'].toString() hasn't executed yet.
The solution is always the same: any code that needs the data from the database has to be inside the then handler, be called from there, or be otherwise synchronized.
In Flutter it is most common to use async and await for this. The key thing to realize is that you can't return something now that hasn't been loaded yet. With async/await you function becomes:
Future<String?> getLikecount(tresc) {
String? likeCount;
var value = await FirebaseFirestore.instance
.collection('Posty')
.where('Tresc', isEqualTo: tresc)
.get();
for (var doc in value.docs) {
var id = element.id;
final value = await FirebaseFirestore.instance
.collection('Posty')
.doc(id)
.get();
likeCount = value.data()!['likeCount'].toString();
print('In then: $likeCount');
}));
print('After then: $likeCount');
return likeCount;
}
Now your code returns a Future<String?> so a value that at some point will hold the string. When calling getLikecount you will now need to use then or await to handle the Future, and if you want to show the count in the UI you will have to store it in the State of a StatefulWidget.
static List categoryList() {
final categorySnapshots = FirebaseFirestore.instance
.collection('categories')
.orderBy('name')
.snapshots();
List categories = [];
categorySnapshots.map((snapshot) => snapshot.docs.map((doc) {
print(snapshot.toString());
categories.add(doc.data()['name']);
}));
print(categories);
return categories;
}
Categories is empty.
How to populate it with the data from snapshots?
I added a new collection called "school", there're two items added inside the document.
void getMessagesTest() async{
QuerySnapshot querySnapshot = await _firestore.collection('school').orderBy('age',descending: true).get();
final allData = querySnapshot.docs.map((doc) => doc.data()).toList();
print(allData);
}
I used my code, and it works. Could you please remove ".where" and try it again?
You could chain where and orderBy together. Please see my code below. Reference link => Using Where and Order by different fields in Firestore query
void getMessagesTest() async{
QuerySnapshot querySnapshot = await _firestore.collection('school').orderBy('age', descending: true).where('age', isGreaterThan: 17).get();
final allData = querySnapshot.docs.map((doc) => doc.data()).toList();
print(allData);
}
Using the below code might help
you can convert the snapshot to Map<String,dynamic> by using the following function:
static Post fromSnap(DocumentSnapshot snap) {
var snapshot = snap.data() as Map<String, dynamic>;
}
I have a users id I want to add it to firestore, like this
['GEcuHm3ICpWlEzfq1Z2tAjI2LII3', 'GEcuHm3ICpWlEzfq1Z2tAjI2LII3' ...]
I tried multiple ways but it didn't work
List membersListUid = [];
Future createGroup() async{
GroupRoomModel newGroup = GroupRoomModel(
groupName: groupName.text,
groupRoomId: uuid.v1(),
owner: userModel.uid,
membersList: controller.membersList,
membersListUid: controller.membersListUid.cast() // <---
);
}
...
Future createGroupFunc() async{
GroupRoomModel newGroup = GroupRoomModel(
groupName: groupName.text,
groupRoomId: uuid.v1(),
owner: userModel.uid,
membersList: controller.membersList,
membersListUid: controller.membersListUid.map((e)=> e).toList() //<---
);
...
Maybe this helps to understand the code
//Controller class
Map<String, dynamic>? userMap;
onSearch() async {
await _fireStore
.collection('users')
.where("email", isEqualTo: searchedMembers.text)
.get()
.then((value) {
userMap = value.docs[0].data();
});
update();
}
membersListUid.add({
"uid": userMap!['uid']
});
It's still gives me map within array.
THE PROBLEM:
membersListUid is a List of Maps. That is why you get an array of Maps in your database.
You need to get the actual value of the uid from each Map by using the uid key to get the value from the map.
THE SOLUTION:
Update this line:
membersListUid: controller.membersListUid.map((e)=> e).toList()
to this below:
controller.membersListUid.map((e)=> (e as Map<String, dynamic>)['uid']).toList()
I have a favourites collection saved under a users collection. Each of the favourite documents has one field which contains a product_Id. I want to retrieve this product_id value and use it to query another collection. This second collection holds the actual products documents.
Retrieving all the documents in the favourite collection. What do I do next to get the value of the product_id fields as strings?
getIdsfromUserFavs(userId) async {
var _favData = await _usersCollectionReference
.doc(userId)
.collection('favourites')
.get();
}
This is the second method that is used to query the products collection. This method needs the String value from above in order to successfully make the query.
Future<QuerySnapshot<Object?>> queryFavsCollection(value) async {
var _favedProducts = await _productsCollectionReference
.where('prod_id', isEqualTo: value)
.get();
print(value);
return _favedProducts;
}
I am using a futureBuilder in the UI.
THis is one way I have tried(The problem with this is that I don't get any data returned):
getIdsfromUserFavs(userId) async {
var _favData = await _usersCollectionReference
.doc(userId)
.collection('favourites')
.get();
var allData = _favData.docs.map((doc) => doc.data()).toList();
allData.forEach((element) async {
String value = element['prod_id'];
print(value);
await queryFavsCollection(value);
});
}
Future<QuerySnapshot<Object?>> queryFavsCollection(value) async {
var _favedProducts = await _productsCollectionReference
.where('prod_id', isEqualTo: value)
.get();
print(value);
return _favedProducts;
}
I can see that the above methods print the ids to the console. But the FutureBuilder doesn't receive any data:
I/flutter ( 4628): 3nHHEWuCDXvbhYfT8ljY
I/flutter ( 4628): MptYFV1oXhflDYkdQyIP
I/flutter ( 4628): Fd2ntXyNVmjn0D6mG3RA
Below function will return all data from favourite collection
Future<QuerySnapshot<Map<String, dynamic>>> getIdsfromUserFavs(userId) async {
QuerySnapshot<Map<String, dynamic>> _favData = await _usersCollectionReference
.doc(userId)
.collection('favourites')
.get();
return _favData; // This will return all data of favourite collection
}
After that you can return List of desire data as shown in below function
Future<List<QueryDocumentSnapshot<Map<String, dynamic>>>> queryFavsCollection(userId) async {
// Will store data in this list so at the end we can return this
List<QueryDocumentSnapshot<Map<String, dynamic>>> favData = [];
QuerySnapshot<Map<String, dynamic>> _favData =
await getIdsfromUserFavs(userId);
for (QueryDocumentSnapshot<Map<String, dynamic>> data in _favData.docs) {
String value = data['prod_id'];
QuerySnapshot<Map<String, dynamic>> _fav = await
_productsCollectionReference
.where('prod_id', isEqualTo: value)
.get();
if (_fav.docs.isNotEmpty) {
_fav.docs.forEach((element) {
favData.add(element);
});
}
}
return favData;
}
Now you can use FutureBuilder as shown below
FutureBuilder<List<QueryDocumentSnapshot<Map<String, dynamic>>>>(
future: queryFavsCollection(userId),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text('Loading...');
}
return Text('you data');
},
);
For better practice kindly refer this. This is from flutter documentation
"The future must have been obtained earlier, e.g. during State.initState, State.didUpdateWidget, or State.didChangeDependencies. It must not be created during the State.build or StatelessWidget.build method call when constructing the FutureBuilder. If the future is created at the same time as the FutureBuilder, then every time the FutureBuilder's parent is rebuilt, the asynchronous task will be restarted."