Firestore calculate values from documents - firebase

I have created a Future which prints out all of the fields from my firestore collection 'products' documents, but this collection is one of many of the same name, as seen below, and therefore I am printing out all of the values of each of the collections documents' fields. I want to add the 'productPrice' for each document that is in it's own collection 'products'
First Products Collection:
Second Products Collection:
My function is listening to all of the 'products' collections. When I try to print the productPrice field values for each of their documents, I get them all printed out, as seen below in the console. I need to add the productPrice values of 29.33 + 39.69 together to make
69.02 but I don't know how to do that without also adding the unrelated document that has the value of 149.99
final FirebaseAuth _auth = FirebaseAuth.instance;
final FirebaseFirestore _cloudStore = FirebaseFirestore.instance;
List<OrderModel> orders = [];
List<ProductModel> orderProductList = [];
Future startListening() async {
User currentUser = _auth.currentUser;
if(currentUser != null){
_cloudStore
.collection("orders")
.doc(currentUser.email)
.collection("orders")
.snapshots()
.listen((event) {
orders = event.docs.map((value){
return OrderModel(
value.data()["name"],
value.data()["date"],
value.data()["dateTime"],
value.data()["status"],
value.data()["productImage"],
);
}).toList();
for(var i = 0; i < orders.length; i++){
if(currentUser != null){
_cloudStore
.collection("orders")
.doc(currentUser.email)
.collection("orders")
.doc(orders[i].dateTime)
.collection("products")
.snapshots()
.listen((event){
orderProductList = event.docs.map((value){
return ProductModel(
value.data()['productName'],
value.data()['productQuantity'],
value.data()['productPrice'],
value.data()['productImage'],
);
}).toList();
print('separate');
event.docs.forEach((value){
var prices = value.data()['productPrice'];
print(prices);
});
notifyListeners();
});
}
}
notifyListeners();
});
} else {
return null;
}
}
My current output in the console:
Restarted application in 881ms.
Reloaded 0 of 983 libraries in 32ms.
flutter: separate
flutter: 149.99
flutter: separate
flutter: 29.33
flutter: 39.69

If I understand the question correctly, It should work if you change your code like that:
double sum = 0.0;
event.docs.forEach((value){
var prices = value.data()['productPrice'];
sum = sum + prices;
print(prices);
});
print(sum);
You can just add that after your print('separate'); statement.

Related

Pagination with StartAfter not working on a firestore collection group

I have the below query which keeps returning the same 5 documents on every call, instead of fetching the next group of documents as I would expect.
DocumentSnapshot<Object?>? lastFetchedDoc;
Future<void> getReviews() async {
Query<Map<String, dynamic>> query = firestore
.collectionGroup("reviews")
.where("city", whereIn: ['New York', 'Philadelphia', 'Washington'])
.orderBy('time_of_posting', descending: true) // timestamp
.limit(5);
if (lastFetchedDoc != null) {
query.startAfterDocument(lastFetchedDoc!);
}
QuerySnapshot snapshot = await query.get();
lastFetchedDoc = snapshot.docs.last;
}
Any ideas what the issue could be here.
Thanks
Calling startAfterDocument returns a new query, so you need to hold on to that return value:
if (lastFetchedDoc != null) {
query = query.startAfterDocument(lastFetchedDoc!);
}

How to delete a doc from a subcollection using multiple filters in FlutterFlow?

I'm using FlutterFlow and my firestore structure is like:
users
contacts
contact_history
events
All are subcollections of "users". My rules are setup such that only users can see/edit/del their data.
I'm trying to delete a specific document from the "contact_history" subcollection, given a set of field values "eventUID" and "contactUID" but the query seems to come up empty and it never deletes the doc.
I'm writing to the console to check values and the params are being passed properly but myLen and iter stay at zero. What am I doing wrong? Do I need to reference the "users" collection somehow?
Future actDelEventContactHist(
String? myEventUID,
String? myContactUID,
) async {
int iter = 0;
int myLen = 0;
print('Begin: actDelEventContactHist -------');
print('myEventUID: $myEventUID');
print('myContactUID: $myContactUID');
WriteBatch batch = FirebaseFirestore.instance.batch();
FirebaseFirestore.instance
.collection('contact_history')
.where('contactUID', isEqualTo: myContactUID)
.where('eventUID', isEqualTo: myEventUID)
.get()
.then((querySnapshot) {
myLen = querySnapshot.docs.length;
print('myLen: $myLen');
querySnapshot.docs.forEach((document) {
iter++;
batch.delete(document.reference);
});
return batch.commit();
});
print('iter: $iter');
print('Docs deleted');
print('END: actDelEventContactHist -------');
Ok, I figured it out. I had to include the 'users' collection as it's the parent. To do so I had to import the firebase_auth package. Solution below...
import 'package:firebase_auth/firebase_auth.dart';
Future actDelEventContactHist(
String? myEventUID,
String? myContactUID,
) async {
// Add your function code here!
int iter = 0;
int myLen = 0;
print('Begin: actDelEventContactHist -------');
print('myEventUID: $myEventUID');
print('myContactUID: $myContactUID');
final myId = FirebaseAuth.instance.currentUser!.uid;
WriteBatch batch = FirebaseFirestore.instance.batch();
FirebaseFirestore.instance
.collection('users')
.doc(myId)
.collection('contact_history')
.where('contactUID', isEqualTo: myContactUID)
.where('eventUID', isEqualTo: myEventUID)
.get()
.then((querySnapshot) {
myLen = querySnapshot.docs.length;
print('myLen: $myLen');
querySnapshot.docs.forEach((document) {
iter++;
batch.delete(document.reference);
});
return batch.commit();
});
print('iter: $iter');
print('Docs deleted');
print('END: actDelEventContactHist -------');
}

How to update document field based on different field value in that document

I have a collection of Users and in there there are 4 fields:
Currently I have a button that increments currentScore of every user by 1 when clicked
Future _getUsersAndUpdate() async {
var querySnapshots = await collection.get();
for (var doc in querySnapshots.docs) {
await doc.reference.update({
'currentScore': FieldValue.increment(1),
});
}
I was wondering how can I increment currentScore by 1 only if currentPick field is set to 1 as well, so every document with a currentPick == 1 should get their currentScore incremented by 1 ?
if I right understand your problem, below lines might be solution your problem.
Future<void> _getUsersAndUpdate() async {
final collectionRef = FirebaseFirestore.instance.collection('users').where('currentPick', isEqualTo: 1);
final users = await collectionRef.get();
if(users.docs.isEmpty) return;
users.docs.forEach(
(doc) async {
await doc.reference.update(
{
'currentScore': FieldValue.increment(1),
},
);
},
);
}

How to sort particular items in model that represent firebase documents of particular collection? (P.S: click below for the well answered question)

Click here for the previous version well solved question by me and others
I want to sort the items in the model which represents the firebase documents of particular collections.Also this model contains the document Ids of the users(which will be sorted according to the distance) of the collection "users" and i will bring those documents only from "users" collection. I have calculated the distances from the current-user to the other users and i want bring the nearest users for this user. I have tried following code:
ScreenShot: [In the pink box area, whole calculation is done and assigned and documents brought from firebase]
[]2
Got Error:
Got this error: "Unhandled Exception: PlatformException(error, Invalid Query. 'in' filters cannot contain 'null' in the value array., null)" –
Detailed Code:
Temp model:
class certainrangeusers {
final String id;
final double away;
final GeoPoint userpoint;
certainrangeusers({this.id, this.away, this.userpoint});
}
Variables:
List<certainrangeusers> info= [];
code:
getUsers() async
{
double radius = 0.3;
String field = "GeoPosition";
print(currentUser.point.longitude);
GeoFirePoint center = geo.point(latitude: currentUser.point.latitude,
longitude: currentUser.point.longitude);
var collectionRef = Firestore.instance.collection('user_locations').document(currentUser.pincode)
.collection('Users_comp lete_address_and_geopoint');
this.stream = geo.collection(collectionRef: collectionRef)
.within(center: center, radius: radius, field: field, strictMode: false);
Future<List<certainrangeusers>> users1 = stream.first.then((documents) => documents.map((doc) =>
certainrangeusers(
id: doc['userPhone'],
userpoint : doc['GeoPosition']['geopoint'],
)
).toList());
users1.then((val) async{
for(var value in val){
info.add(certainrangeusers(
//away: await Geolocator().distanceBetween(currentUser.point.latitude,currentUser.point.longitude, value.userpoint.latitude, value.userpoint.longitude),
away: center.distance(lat: value.userpoint.latitude,lng: value.userpoint.longitude),
));
info.sort((a,b) => a.away.compareTo(b.away));
}
List ids = [];
for(var value in info){
ids.add(value.id);
}
QuerySnapshot snapshot = await Firestore.instance.collection('users').where('id', whereIn: ids).getDocuments();
List<User> users = snapshot.documents.map((doc) => User.fromDocument(doc)).toList();
setState(() {
this.users = users;
});
});
}
The error message is telling you that you can't have a null value in the array that you use for this query:
Firestore.instance
.collection('users')
.where('id', whereIn: ids)
.getDocuments();
You're going to have to figure out why ids contains a null value and fix that. We can't see where that's coming from based on what you're showing here.

Get array of ID from Firebase (DART/Flutter)

Is there any way to fetch data from Firebase with an array of documents.
Now I do this with loop. It works but maybe there is some more efficient way to fetch data? Members list can contain up to 10k users so create 10k requests seems wrong.
Many thanks!
ref = db.collection('users');
Future<List<User>> fetchAllMembers({List<dynamic> members}) async {
List<User> results = [];
for (String userID in members) {
await ref.document(userID).get().then((result) {
results.add(User.fromMap(result.data, result.documentID));
});
}
return results;
}
SOLVED
So simple :). Working example below. Many thanks!
final Firestore db = Firestore.instance;
ref = db.collection('users');
List<dynamic> membersIDS = ['DSGSGSG', 'IBIOSCP3S', 'ASDUASDGU'];
/// Fetch members list
Future<List<User>> fetchAllMembers({List<dynamic> membersIDS}) async {
/// With whereIn
var result = await ref.where('uid', whereIn: members).getDocuments();
var documents = result.documents.map((doc) => User.fromMap(doc.data, doc.documentID)).toList();
return documents;
/// With loop
// List<User> results = [];
// for (String userID in members) {
// await ref.document(userID).get().then((result) {
// results.add(User.fromMap(result.data, result.documentID));
// });
// }
// return results;
}
Query documents where the given field matches any of the comparison values
userRef.where('id', 'in',
[['DSGSGSG', 'IBIOSCP3S', 'ASDUASDGU']]);

Resources