Filtering with just one parameter in a list of firestore collection in flutter - flutter

I am creating a chat app where people join groups, I have been able to create the groups and allow people to join in, anytime a user joins I save the group object into the user collection, so as to fetch for some other time, now what I want to achieve is fetching all user where group ID is the same value. here is what I have tried.
getUsersInCircle(String circleID) async {
userList.clear();
try {
QuerySnapshot<Map<String, dynamic>> ref = await db
.collection(AppStrings.users)
.where("circles", arrayContains: circleID)
.get()
.then((QuerySnapshot<Map<String, dynamic>> value) {
if (value.docs.isNotEmpty) {
userList.assignAll(
value.docs.map((e) => UserModel.fromJson(e.data())).toList());
print(value.docs.first.data());
} else {
print("no data");
}
return value;
});
return ref;
} catch (e) {
print(e.toString());
}
}
This is what my firestore database looks like
enter image description here
What I want to filter by is the circle Id but it does not return any data

i think i found the problem, you are storing an map inside the circles array, not as a normal array.
this is the difference between an map and array in Firestore
map vs array
Query an array:
where("circles", arrayContains: circleID)
Query an map
where("circles.circleID", isEqualTo: circleID)

Related

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])

What would be the better way to write this dart iteration and return a list

The purpose is to do some sort of join. Get each user doc from the user document in firestore and attach it to some collection by uid. Then return the collection with the user document full details rather than just the uid.
Future<List<ChatRoom>> getChatsrooms(uid) async {
ChatRoom chatroom = new ChatRoom();
try {
List<ChatRoom> chatrooms = new List();
var snapshots = await _db
.collection('my-chats-chats')
.where('users', arrayContains: uid)
.orderBy('updated_at', descending: true)
.get();
for (var room in snapshots.docs) {
chatroom.chatroomid = room.data()['chatroomid'];
chatroom.users = room.data()['users'];
// get user profile that isn'nt u.
List<dynamic> userids = await room.data()['users']
..remove(uid);
var doc = await _db.collection('my-chats-users').doc(userids[0]).get();
UserModel user = UserModel.fromMap(doc.data());
chatroom.users.add(user);
// Remove the users string UID from users list
chatroom.users.remove(user.uid);
chatroom.users.remove(uid);
chatrooms.add(chatroom);
}
return chatrooms.toList();
} catch (e) {
print("Couldn't get user\'s chatrooms exception: " + e.toString());
return null;
}
}
The above seems to do what I want, except the chatrooms list returned, only contains duplicates of one chat room. So even there are 10 different chat rooms, I am only getting duplicates of one chatroom 10 times.
What I am thinking of is the chatrooms.add(chatroom); only adds one item. But the chatrooms list is supposed to be a growable list. So why is it ending up with just one duplicated item?
What would be the better way to write this?

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'];
}

How to get data from nested collection in Flutter firestore?

I am using provider and Stream to fetch data from Firestore. so now i want to access the inner collection. but i am not able to fetch the data. How can i access myOrders collection.
this is the structure of firestore.
i tried this code to fetch but not worked for me.
//Store data into myOrders collection
Future myOrders(String image, String price) async {
final FirebaseUser user = await _auth.currentUser();
return await userData
.document(user.uid)
.collection('myOrders')
.document()
.setData({
'orderedImage': image,
'orderedPrice': price,
});
}
// get the data as snapshot
List<OrderedModel> myOrderSnapShot(QuerySnapshot snapshot) {
return snapshot.documents.map((doc) {
return OrderedModel(
orderedImage: doc.data['orderedImage'] ?? '',
orderedPrice: doc.data['orderedPrice']);
}).toList();
}
// get the snapshot as stream
Stream<List<OrderedModel>> get orderedStream {
return userData.document(uid).collection('myOrders').snapshots().map(myOrderSnapShot);
}```
did you try printing the values and debug the code?

How to upload contacts as Iterable from Flutter to Firestore

I'm creating an app which will upload all contacts to Firestore database with map type. But below code do not upload contacts to Firestore. Please help.
I have been trying to fetch contacts from my phone to Firestore using Flutter app. I used contact_services library to fetch contacts. Even after trying some similar examples, I could not my contacts to Firestore using map type. Where do I make changes so that I can upload all my contacts as map value to Firestore
final Iterable<Contact> contacts = await ContactsService.getContacts(withThumbnails: false);
Firestore.instance
.collection('contacts')
.document(firebaseUser.uid)
.setData({
'contact':{ contacts.map((Contact contact){ 'name': contacts.displayName,contacts.phone})}
});
I expected to display all my contacts in firestore with map type, but actual output is none were uploaded.
I am sure you have fixed this since this is an old post. But there are a few things incorrect with how you are using the map method id Dart.
You named your element variable "contact" and not "contacts" so that is the variable you should be referencing "contact" to get your information. So it would be contact.displayName.
You are not returning anything. Because there is no "=>" there is no implicit return and because there is no "return" there is no explicit return.
Also, what you are returning from the map method is an Iterable to the contact field.
I am not sure what you are trying to accomplish here. Are you trying to insert a nested object? If so, your phone is also missing a key
Little late but, this is for the reference for the Firestore version ^0.16.0.
// your list of contacts in _contacts.
List<Contact> _contacts = [];
final FirebaseFirestore _db = FirebaseFirestore.instance;
CollectionReference _ref = _db.collection(collectionName);
Future<void> syncContacts({uid}) async {
try {
Map<String, dynamic> _data;
if (_contacts != null)
_data = {
'contacts': _contacts
.map((k) => {
'name ': k.displayName,
'phone': k.phones.first.value
.toString()
.replaceAll(new RegExp(r"\s\b|\b\s"), "")
.replaceAll(new RegExp(r'[^\w\s]+'), '')
})
.toList(),
};
log(_data.toString());
await _service.reference().doc(uid).set(_data, SetOptions(merge: true));
} catch (e) {
log(e.toString());
} finally {
notifyListeners();
}
}
P.S I have used flutter_contact library to get contacts from the device.