Flutter - How to add a field to all documents in firebase collection - firebase

I am using flutter firebase. And I want a query to add a key and value to all documents in firebase collection.
I try to use batch write but it add a new documents having field. But not merge to existing documents.
var db= Firestore.instance();
var batch = db.batch();
batch.setData(
db.collection("users").document(),
{"status": "Approved"}
);
When I try to give document Id like document('id') it add only to that document.
I try many and watches YouTube videos but not able find still now. Please help me !

Create a dummy button on one of the pages in your app. Pressing the button should add the field in all documents of the particular collection.
Here, I have used an IconButton to add an empty field called 'bio' in the 'users' collection.
You can delete the button later after you've added the field in your documents because this is your (developer's) problem, and your app user does not need the button.
IconButton(
onPressed: () {
FirebaseFirestore.instance
.collection('users')
.get()
.then(
(value) => value.docs.forEach(
(element) {
var docRef = FirebaseFirestore.instance
.collection('users')
.doc(element.id);
docRef.update({'bio': ''});
},
),
);
},
icon: Icon(Icons.done),
),

This is because you're using the setData() method, instead you should use the updateData() to update:
var db= Firestore.instance();
var batch = db.batch();
batch.updateData(
db.collection("users").document(),
{"status": "Approved"}
);

Related

error in saving two users chat in flutter

I was making chat app in flutter with firebase. I was able to save the users chat in firebase by this function:
await FirebaseFirestore.instance
.collection("Chats")
.doc(uid! + FirebaseAuth.instance.currentUser!.uid)
.collection("messages")
.add({
FirebaseAuth.instance.currentUser!.uid:
chatController.text,
}).then((value) => () {
b = uid;
});
but when I save the one users chat. I was thinking that when I will get the chat of second user. It will return a chat from the doc I was saving the both users chat. But unfortunately when I save the users chat it saves a new doc named first users id and then second users id, in first users chat it saves doc named the second user id and first users id. I know what is the reason from which it was happening but how can I resolve that, I mean how can I save the both users chat in one doc
Update: the function I have tried based on Frank's answer:
var docId = uid
.toString()
.compareTo(FirebaseAuth.instance.currentUser!.uid) > 0;
the function used for printing docId:
IconButton(
icon: Icon(Icons.send),
iconSize: 20.0,
onPressed: () async { print(docId);}
)
You need to have a deterministic ID for the document.
One simple way to do this is to always alphabetically order the two UIDs with something like this:
const docId = uid!.compareTo(FirebaseAuth.instance.currentUser!.uid) > 0
? uid! + FirebaseAuth.instance.currentUser!.uid
: FirebaseAuth.instance.currentUser!.uid + uid!
await FirebaseFirestore.instance
.collection("Chats")
.doc(docId)
...
For more on this, see the examples in my answer here: Best way to manage Chat channels in Firebase

Flutter Firebase Pagination - Nested Query

I am relatively new to the Flutter world and need some help in efficiently querying a nested Firebase query with pagination in Flutter.
I am building an app where I have a few thousand of user selected documents in collectionA (selected from >100k documents from collectionB) and need to loop through a chunk of 10 documents (whereIn limit of 10) queried via stream. My current implementation (snippet below) takes a list of document ID's "d" and chunks in a list of 10 via quiver/iterables. The drawback of the methodology is that it reads thousands of user documents upfront before displaying it in the app. I would like to use a pagination and control the reads.
Would you suggest a solution (with a code snippet) on how to use the pagination through thousands of user selected documents?
Future<List<Article>> fbWhereGT10Article(
String collection, String field, List<dynamic> d) async {
final chunks = partition(d, 10);
// print(chunks);
final querySnapshots = await Future.wait(chunks.map(
(chunk) {
Query itemsQuery = FirebaseFirestore.instance
.collection(collection)
.where(field, whereIn: chunk);
// .orderBy('timestamp', descending: true);
return itemsQuery.get();
},
).toList());
return querySnapshots == null
? []
: await Stream.fromIterable(querySnapshots)
.flatMap((qs) =>
Stream.fromIterable(qs.docs).map((e) => Article.fromFirestore(e)))
.toList();
}

Firebase receive documentID when adding and updating documents to firebase with flutter

I am adding a new document to my firestore group 1, and use the new documentID of that group to update two other documents. Afterwards, I'd like to save the documentID from group 1 in a variable in order to pass it to my widgets.
How can I receive and save the documentID when adding a new document to group 1 without causing an extra firestore read? I don't understand why the code below works except for
valueId = value.documentID
Thanks
onPressed: () {
firestore.collection('Gruppe').add({
'Group': messageTextController.text.trim(),
'Gruppenersteller': loggedInUser.uid,
'Gruppenmitglieder': FieldValue.arrayUnion([
loggedInUser.email,
widget.userEmail,
]),
'Angelegt': FieldValue.serverTimestamp(),
}).then((value) => {
firestore
.collection('Nutzer')
.document(loggedInUser.uid)
.updateData({
'Slates': FieldValue.arrayUnion([value.documentID])
}),
firestore
.collection('Nutzer')
.document(widget.userNutzerId)
.updateData({
'Slates': FieldValue.arrayUnion([value.documentID])
}),
valueId = value.documentID,
});
print('valueID');
print(valueId);
You can get the random ID of a document before it's added like this:
val docRef = firestore.collection('Gruppe').doc()
val docId = docRef.documentID;
Then you can go on and create the document with set():
docRef.set(...)
In your code above, I would expect that print(valueId) to not print the assigned value of value.documentID, because add() and then() are asynchronous and return immediately with a Future. In fact, any function that returns a Future will do so immediately. The callback you provide to then() will be invoked some time later, after the operation is complete. So, effectively, your code is trying to print the document ID before it's been assigned. That's why I'm suggesting that you get it immediately of the reference instead of trying to get it later.

Flutter Firebase How to get random document

I am trying to get some random posts from Firebase. But i am unable to get random document id.
Is there any way to retrieve data from Firebase like this :-
getRandomData() async {
QuerySnapshot snapshot = await posts
.document(random.id)
.collection('userPosts')
.getDocuments();}
i am trying to say that. Now i am able to get documentID normally not in italics.so now how can i get random documentID from Firebase.
List documentIds in a list first.
var list = ['documentId1','documentId2','documentId3'];
var element = getRandomElement(list);
Then query the documentSnapshot
You can first get all documents in you collection.
Try this code:
async getMarker() {
const snapshot = await firebase.firestore().collection('userPosts').get();
const documents = [];
snapshot.forEach(doc => {
documents[doc.id] = doc.data();
});
return documents;
}
Next, from return documents you can create a list of documents id and get random numbers (document id) from this list.
The main problem here that's going to prevent you from moving forward is the fact that you don't actually have any documents nested immediately under "posts". Notice that the names of the documents are in italics. That means there isn't actually a document here at all. The reason why they are show, however, is because you have a subcollection "userPosts" nested under the path where that document ID exists.
Since you don't have any documents at all under "posts", the usual strategies to find a random document won't work at all. You're going to have to actually populate some data there to select from, or find another way to select from the data in the subcollections.
firestore()
.collection('SOURCE')
.doc(props?.route?.params?.data?.id)
.collection('userPosts')
.get()
.then(querySnapshot => {
querySnapshot.forEach(documentSnapshot => {
console.log('User ID: ', documentSnapshot.id, documentSnapshot.data());
})
})

how to retrieve unknown sub collection from document in flutter

I have the following code with the objective of retring all the documents like this: Collection('A').document(currentUser), this should give me the document YRZ1**** as you may see in the first image. Now what I want to do is get all the documents in the t22o9*** subcollection, as showned on the second image, how can I do that?
var docPath=Firestore.instance.document('Messages/$currentUser');
docPath.snapshots().listen((event) {
print('Hello 12 ${event.data}');
});
In order to get data from subcollection you can do the following:
var db = Firestore.instance;
//This is a reference to the YRZ1**** doc
var messagesDoc = db.collection('Messages').document('Messages/$currentUser');
//collectionId is the t22o9*** id, you need to have this set previosly in your code
var docList = [];
messagesDoc.collection(collectionId)
.getDocuments()
.then((QuerySnapshot snapshot) {
snapshot.documents.forEach((doc) => docList.add(doc)'));
});
With this code, docList will be a list of the documents located at your subcollection t22o9*** of the YRZ1*** document.
Also you can check this link with some examples on how to get data from firestore using flutter.
EDIT:
As per what you have clarified on the comments, getting the subcollection data is a bit more complicated with subcollections that were created dynamically, as you can see on this link, which I assume is the case you have. The most feasible solution in your case would be to create a list of ids of subcollections in your parent document, so for example your YRZ1*** document would have this structure
document
id: YRZ1***
subCollectionIds : [subCollectionId1, subCollectionId2,...]
subCollection1
subCollection2
...
subCollectionN
Having this structure you could use this code to retrieve the list of subcollections and the first document of each subcollection, ordered by whatever field you'd like:
var db = Firestore.instance;
var listFirstDocSub = []
//This is a reference to the YRZ1**** doc
db.collection('Messages')
.document('Messages/$currentUser')
.getDocument()
.then((DocumentSnapshot doc) {
var listSubCollections = doc["subCollectionIds"];
listSubCollections.forEach((id) {
db.collection('Messages')
.document('Messages/$currentUser')
.collection(id)
.orderBy("WHATEVER_FIELD_YOU_DECIDE")
.limit(1)
.getDocuments()
.then((DocumentSnapshot snapshot) {
listFirstDocSub.add(snapshot);
})
});
});
NOTE: With this approach, everytime you add a new subcollection, you will also need to add it's id to the subCollectionIds list.
Hope This helps.

Resources