Flutter: add data to Map (instead of replacing data) - flutter

The following transaction completely replaces the data in a Firestore Map when run:
DocumentSnapshot docSnapshot = await tx.get(docRef); // doc Snapshot
if (docSnapshot.exists) {
await tx.update(
docRef,
<String, dynamic>{
'Users': {
'user.uid': {'name': user.displayName, 'date': DateTime.now()},
}
},
);
What would be the correct way to add to a map instead of replacing the existing data, the same way FieldValue.arrayUnion works?

Since you already fetched the data you could take the map out from the snapshot, replace the data there and call the update with the altered map.

Related

How can I access each document id in Firebase?

In my blogapp ,I am trying to implement comment system in flutter using cloud firestore. Each document is a post and I am trying to add comments as a subcollection to each document. How can I access each document id so that I can access the subcollection ?
Here I tried to print the document id below but it shows error NoSuchMethodError: 'id' method not found Receiver: null Arguments: [] :
final ref = await FirebaseFirestore.instance
.collection('blogs')
.add({
'title': titleController.text,
'body': myController.text,
'author': name,
'date': DateFormat('dd/MM/yyyy,hh:mm')
.format(DateTime.now()),
})
.then((value) => successAlert(context))
.catchError((error) =>
errorAlert(context));
titleController.clear();
myController.clear();
print(ref.id);
}
This is my firestore database :
You need to have access to the document id inside blogs, and access it's collection and the add your data like this...
await FirebaseFirestore.instance
.collection('blogs')
.doc(documentId) // you need to enter this document id
.collection('comments').add({
'title': titleController.text,
'body': myController.text,
'author': name,
'date': DateFormat('dd/MM/yyyy,hh:mm')
.format(DateTime.now()),
})
When you dont have the document id Firebase provides the get() command which returns the content of a collection. Like this:
db.collection("cities").get().then((res) => print("Successfully completed"), onError: (e) => print("Error completing: $e"));
But i realize that you will need the document id, so to get this you have to store the id after inserting a post, i've an example from a personal project:
await firestore.collection('item').add({
'quantity': element.quantity,
'product_id': element.product.productId,
}).then((value) {
/// Here you can access [value.id] to get this document id.
/// Now you can save it in a list or a class instance. Just keep it.
})
Now you can use the document id to update the post with a new comment, like this. For more information we have the Firestore documentation with flutter code snipets.

Flutter how to delete field from firebase array

I am trying to delete a field from my firebase array. I am using this code but it deletes then whole activity array.
FirebaseFirestore.instance
.collection(
widget.user.user.uid)
.doc(documentName)
.update({
"activities":
FieldValue.delete()
Instead I want to delete a specific field from 'activities' like activities[2]. How can I do to fix this?
To remove an item at a specific index you can use the arrayRemove method from FieldValue
FirebaseFirestore.instance.collection(widget.user.user.uid).doc(documentName).update({
"activities": FieldValue.arrayRemove("itemToRemove")
})
You should try using FieldValue.arrayRemove() method and then pass the value that you want to remove using this :
var val=[]; //blank list for add elements which you want to delete
val.add('$addDeletedElements');
FirebaseFirestore.instance
.collection(
widget.user.user.uid)
.doc(documentName)
.update({
"activities":
FieldValue.arrayRemove(val])
You have to tell firebase full path like this
FirebaseFirestore.instance
.collection("chat_dialog")
.doc("India")
.collection("dialog_details")
.where(['firestore_id'].contains('your_value'))
.get()
.then((value) {
print(value.docs.length);
for (var element in value.docs) {
print(element.id);
}
});

How to update all collection in firebase firestore in flutter

I have two collections. One collection "User", who contains the user info (name...) And one collection "Post" who contains all posts of my flutter application. A post document contains many fields like a "Title", "Name" of the user. I add an option in my application to allow the user to change his name. But I must change the name in the "User" collection and in all posts it creates in the "Post" collection. How should I do it? Can anyone help me with an example?
There's nothing magical here. You'll need to get all post documents for that user with a query, and then update them one by one or in batches.
I'd also recommend checking out: What is the fastest way to write a lot of documents to Firestore?
Depends on which firestore are you using.
For Cloud Firestore:
You can update like this way, this is the case where you are updating just one field of your user.
final docRef = db.collection("users").doc("user_id");
final updates = <String, dynamic>{
"timestamp": FieldValue.serverTimestamp(),
};
docRef.update(updates).then(
(value) => print("DocumentSnapshot successfully updated!"),
onError: (e) => print("Error updating document $e"));
For updating a nested field:
// Assume the document contains:
// {
// Title: "Post Tittle",
// Name: "Post Name"
// user: { id: "1", name: "User Name" }
// date: "2022-12-08"
// }
db
.collection("posts")
.doc("post_id")
.update({"date": "2022-13-08", "user.name": "New name"});
You can see more details here: https://firebase.google.com/docs/firestore/manage-data/add-data
Assuming there is a user id attached to each post, you can query from the posts collection where the user (that is changing his/her name) id matches the id that is in the post (from the posts collection) and then modify the user property/attribute from the results.
A sample code would look like this,
To modify from the user collection
final docRef = FirebaseFirestore.instance
.collection('users')
.doc(id);
final response = await docRef
.update(updatedDateInJson)
.then((value) => value)
.onError((error, stackTrace) => error);
To modify from the posts collection where the user is found in a post
final response = FirebaseFirestore.instance
.collection('posts')
.where('name', isEqualTo: 'John')
.get()
.then((value) async {
// modify each doc
});
Quick Note: use a onError block to check for errors in updating docs.

Flutter get single variable from a list?

I am getting data from firestore like this
CollectionReference _collectionRef =
FirebaseFirestore.instance.collection('Users');
QuerySnapshot querySnapshot = await _collectionRef.get();
// Get data from docs and convert map to List
final allData =
querySnapshot.docs.map((doc) => doc.data()).toList();
print(allData);
its printing data in list format like this
I/flutter (13500): [{number: +123131, shopname: ishaq shop, id: here i need doc id , lastupdate: , sendQty: }, {number: +1231231, shopname: ishaq shop, lastupdate: , id: gXVR4Sp3Cm3pii97Gh00, sendQty: }, {number: +123131, shopname: ishaq shop, lastupdate: , id: AM8KL6SxvFkCRQqpTjre, sendQty: }]
I just want to get a number from a list. I try something like
print(allData['number']);
print(allData.number);
but not working for me
Try this. If it works you can iterate it through your list.
You convert your data to list here then try to call like a map. The reason why it is wrong. and replace final with list. It works fine
List allData =
querySnapshot.docs.map((doc) => doc.data()).toList()
Try
print(allData[0]['number']);
allData is a List<Map<String, dynamic>>, it means a list of maps (map: also called dictionary in java/swift and other language).
To Access a single variable you need the index of the dictionary first then use the key to access it.
var number = allData.first['number'];
print(number);
Right here I am printing the first item of the list, but you can access any item you want as long as you have its index.

Firestore new document inside writebatch

I have a couple of writes that I want to be done together.
So I used a write batch.
Since the write batch requires a document reference, I have been creating the document before that write batch operation.
DocumentReference accountHistoryDoc = await queryResult.reference.collection('accountHistory').add({});
This led to many empty documents. Since I'm still testing and debugging the app, I assume because of an exception after the creation of the document.
How can I make sure that an empty document isn't created in the case of failure?
I'm thinking of changing this line
wb.set(
accountHistoryDoc, // Change this line
{
'account': newAccount,
'serverTimestamp': FieldValue.serverTimestamp(),
'type': 'hisab',
},
);
to
wb.set(
await subscriberDoc.collection('accountHistory').add({}),// new line
{
'account': newAccount,
'serverTimestamp': FieldValue.serverTimestamp(),
'type': 'hisab',
},
);
Is this my thinking correct?
Rest of code:
QuerySnapshot query = await FirebaseFirestore.instance
.collection(CurrentUser.getCurrentUser().uid)
.where('mobile', isEqualTo: mobile)
.get();
QueryDocumentSnapshot queryResult = query.docs.first;
DocumentReference subscriberDoc = queryResult.reference;
DocumentReference accountHistoryDoc = await queryResult.reference.collection('accountHistory').add({}); // < -- new empty document here
WriteBatch wb = FirebaseFirestore.instance.batch();
// update the total account
wb.update(
subscriberDoc,
{
'totalAccount': subscriber.totalAccount + newAccount,
},
);
// add new document in account history
wb.set(
accountHistoryDoc,
await subscriberDoc.collection('accountHistory').add({}),
{
'account': newAccount,
'serverTimestamp': FieldValue.serverTimestamp(),
'type': 'hisab',
},
);
If you call CollectionReference.doc() without an argument, it generates a new unique DocumentReference without already creating that document in the database. You can then use this DocumentReference to create the new document inside the batched write.
Also see the documentation for the FlutterFire doc() method.