Flutter Firebase whereContains two values [duplicate] - flutter

This question already has answers here:
Firestore search array contains for multiple values
(6 answers)
Closed last month.
Here is my code. I have two input parameters authUser and chatUser. I have a record called Chats, with a List field called users. I want to query and get the document where the List field users contains BOTH authUser and chatUser.
import 'package:cloud_firestore/cloud_firestore.dart';
Future<ChatsRecord> getChatDocFromChatUserAuthUser(
DocumentReference? chatUserRef,
DocumentReference? authUserRef,
) async {
// Add your function code here!
ChatsRecord chatDoc = await FirebaseFirestore.instance
.collection('chats')
.where("users", arrayContains: chatUserRef)
.where("users", arrayContains: authUser)
.get()
.then((snapshot));
return chatDoc;
}
Here is the error I get from trying the solution below:
lib/custom_code/actions/get_chat_doc.dart:23:34:
Error: A value of type 'List<QueryDocumentSnapshot<Object?>>' can't be returned from an async function with return type 'Future<List<ChatsRecord>>'.
- 'List' is from 'dart:core'.
- 'QueryDocumentSnapshot' is from 'package:cloud_firestore/cloud_firestore.dart' ('/root/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-4.2.0/lib/cloud_firestore.dart').
- 'Object' is from 'dart:core'.
- 'Future' is from 'dart:async'.
- 'ChatsRecord' is from 'package:counter_party/backend/schema/chats_record.dart' ('lib/backend/schema/chats_record.dart').
return (await snapshots.first).toList();
^
Error: Compilation failed.

You should try using conditions from QuerySnapshots by :
CollectionReference chatDoc = Firestore.instance.collection('chats');
final snapshots = chatDoc.snapshots().map((snapshot) => snapshot.documents.where((doc) => doc["users"] == chatUserRef || doc["users"] == authUser));
return (await snapshots.first).toList();

Related

flutter firestore: how to get a query of documents

Im trying to get a list of user objects from firestore through a query. My current attempt looks like this:
List<User> getDiscoveryUsers(
String userId,
) async {
Query<Object?> query =
userCollection.where('finishedOnboarding', isEqualTo: true).limit(10);
var collection = await query.get();
//get the users list from query snapshot
var users = collection.docs.map((doc) => User.fromSnapshot(doc)).toList();
return users;
}
However I am getting the error:
Functions marked 'async' must have a return type assignable to 'Future'.
Try fixing the return type of the function, or removing the modifier 'async' from the function body.
I know there are a few similar questions on stack overflow, but i just cant seem to get this to work. Anyone know whats going on?
Thanks!
Just change the return type of your function from List<User> to Future<List<User>>.
Happy coding:)
your return type should be Future and must wait with await when running query on firestore.
Future<List<User>> getDiscoveryUsers(
String userId,
) async {
Query<Object?> query =
userCollection.where('finishedOnboarding', isEqualTo: true).limit(10);
var collection = await query.get();
//get the users list from query snapshot
var users = collection.docs.map((doc) => User.fromSnapshot(doc)).toList();
return users;
}

How to update nested field inside a document in Firestore Flutter

I am working with Flutter and Cloud Firestore, and I'm stuck on the point where I need to update a nested field inside my collection -> document. Below is the screenshot of my firestore collection structure. I know how to do basic update method like FirebaseFirestore.instance.collection('collection_path').doc('data').update(...), however, in my case, the document structure is a bit complex so I need some help in case of performing update method.
Here, I need to change (on a button press) the field status to true/false under strategies array.
I have the access to strategyName field so that I could get that item in the strategies array and change it...
What I tried:
ElevatedButton(
onPressed: () async {
// status=true
final value = await FirebaseFirestore.instance
.collection(widget.symbol + '_Live')
.doc("data")
.get();
final data = value.data();
final strategies =
data!['strategies'] as List<Map<String, dynamic>>;
final strategy = strategies.firstWhere(
(item) => item['strategyName'] == strategyName,
orElse: () => Map());
strategy['status'] = true;
await FirebaseFirestore.instance
.collection(widget.symbol + '_Live')
.doc("data")
.update(data);
},
child: Text("Start"),
),
Obviously, this won't work because here I'm just changing it locally, i.e. not using the Firestore update method to actually change the field. But I'm confused as to how to update that nested field.
Any leads/help would be really appreciated!
EDIT:
I did as you told and edited my answer, but now the error is gone but nothing seems to work, i.e. in firestore, there is no change in the data doc.
ERROR: Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<Map<String, dynamic>>' in type cast
You need to update value map locally, then store it back:
final value = await FirebaseFirestore.instance
.collection(symbol + '_Live')
.doc("data")
.get();
final data = value.data();
final strategies =
data!['strategies'].map((item) => item as Map<String, dynamic>).toList();
final strategy = strategies.firstWhere(
(item) => item['strategyName'] == strategyName,
orElse: () => Map());
strategy['status'] = toggleValue;
await FirebaseFirestore.instance
.collection(symbol + '_Live')
.doc("data")
.update(data);
The point is to store the entire value.
EDIT by Author : Just needed to map each element to Map<String, dynamic>.

Flutter - cloud_firestore 2.5.x- null safety update : query startAfterDocument keep initializing from first document

Since updating my flutter project to :
null safety
With cloud_firestore 2.5.x requiring to specify the type
Map<String, dynamic> for DocumentSnapshot according to
After updating cloud firestore: The operator '[]' isn't defined for the type 'Object'. Try defining the operator '[]'
my query with startAfterDocument keep resending the same results starting from 0.
Query<Map<String, dynamic>> queryColl = FirebaseFirestore.instance
.collection('customers')
.doc(customerId)
.collection('ledger_transactions')
.limit(iLimit)
.orderBy('created_at', descending: true);
if (lastDoc != null) {
print('getCustomerLedger lastDoc != null ${lastDoc.id}');
queryColl.startAfterDocument(
lastDoc!);
}
QuerySnapshot<Map<String, dynamic>> snapshot = await queryColl.get();
I cannot figure out in the documentation and S.O what has been changed in specs. Doesnt work also with StartAt/StartAtDocument/StartAfter
Queries in Firestore are immutable once you construct them. So when you call startAfterDocument that returns a new query, that you need to assign to queryColl again.
Something like:
queryColl = queryColl.startAfterDocument(
lastDoc!);
}

Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<Map<dynamic, dynamic>>' Flutter Firebase

I am trying to get a list from firebase document and then set to another empty List of maps then add a map to this list of maps and pass it back to Firebase.
This is My method:
Future logFinalWorkout(user, finalWorkout) async{
List<Map<dynamic, dynamic>> result = List<Map<dynamic, dynamic>>();
await users.document(user.uid).get().then((doc){
result = doc.data['finalWorkouts'];
result.addAll(finalWorkout);
});
return await users.document(user.uid).updateData({
'finalWorkouts' : result,
});
}
finalWorkout parameter is of type Map<dynamic,dynamic>
final workouts represents the list coming from Firebase. I keep getting the above error
Remove List<Map<dynamic, dynamic>> result and add List< dynamic> result instead of that. Give it a try.

FLUTTER FIRESTORE -Query the field and get document id and check other field

am trying to get the searched value(userid) which is in the field of a document in firestore I want to check the other fields(status) of the document I tried this method but failed
handlesubmit(BuildContext context)async{
final QuerySnapshot searcheduserid=
await Firestore.instance.collection('users')
.where('userid',isEqualTo: userid).limit(1).getDocuments();
final userdocid=searcheduserid.documents.map((doc)=>doc.documentID);
final DocumentSnapshot getuserdoc= await Firestore.instance.collection('users')
.document(userdocid).get();
final userstatus = getuserdoc.data['status'];
// I GET AN ERROR HERE ERROR SAYS
// METHOD [](status) was called on null
if(userstatus==null){
return showdialog( context,'the entered user id status does not exist');
}
}
You probably copied an older version of your code because it is unlikely that your code compiles the following line of your program:
final DocumentSnapshot getuserdoc= await Firestore
.instance
.collection('users')
.document(userdocid).get();
The error message on my system is:
The argument type 'Iterable<String>' can't be assigned to the parameter type 'String'.
Which means that userdocid is an Iterable of type String (Iterable<String>), but a parameter which is of type String is expected.
You have multiple options of fixing the problem, but I suggest the following:
Since you are only expecting one document from your QuerySnapshot it is enough to just look at the first document.
final QuerySnapshot searchedUserId = await Firestore.instance
.collection('users')
.where('userid', isEqualTo: userid)
.limit(1)
.getDocuments();
// if it is possible that searchedUserId returns no document make sure to
// check whether searchedUserId.documents.length > 0,
// otherwise searchedUserId.documents.first will throw an error
DocumentSnapshot document = searchedUserId.documents.first;
final userDocId = document.documentID;
final DocumentSnapshot getuserdoc =
await Firestore.instance.collection('users').document(userDocId).get();
Improved Solution:
However I think your code is a bit redundant anyways, because you are looking up a field of a document which has the same value as the document ID. You could shorten the whole code to
final DocumentSnapshot getuserdoc =
await Firestore.instance.collection('users').document(userid).get();
Error calling getuserdoc.data['status']
If you get an error saying something similar to
[](status) was called on null
Then that means getuserdoc has no value. This is likely due to the fact that there is no such database entry with the given ID. Check if the ID is in your database, otherwise comment below for additional information, because the provided code had compilation errors and does not run at all.