Flutter: How can use FieldValue.arrayRemove? - firebase

How can I delete an array of array of objects from Firestore? I want to delete it inside a list.generate
Here is my database structure, I want to delete [{street A, number 25}]
List.generate(
...
IconButton(
icon: const Icon(CupertinoIcons.trash),
onPressed: () async {
try {
await FirebaseFirestore.instance
.collection('users')
.doc(data['uid'])
.update(
{
'adress':
FieldValue.arrayRemove(
??)
},
);
} catch (e) {
print(e);
}
},
),
)),

As I see in your screenshot, the adress field is not of type array, it's a Map:
So there is no way you can call FieldValue.arrayRemove. If you want to remove that field, then please use the following lines of code:
Firestore.instance.collection('users').document(data['uid']).set(
{'adress': FieldValue.delete()},
SetOptions(
merge: true,
),
)
Edit:
After you have updated the screenshot, now the adress field is indeed of type array:
If you want to delete a specific object from the array using FieldValue.delete(), you should use all the data in the object and not partial data. I have even written an article regarding updating an array of objects in Cloud Firestore:
How to update an array of objects in Firestore?
Edit2:
In code it should look like this:
Firestore.instance.collection('users').document(data['uid']).update({
'adress': FieldValue.arrayRemove(elementToDelete),
});
Please note that elementToDelete object should contain both fields populated. The number should hold the value of "25" and street should hold the value of "street A". It will not work if you use only one.
However, if you thought that Firestore provides a direct way to delete an array element by index, please note that is not possible. In such a case, you'll have to read the document, remove the element from the array, then write the document back to Firestore.

Related

How to make changes to a DocumentSnapshot/QueryDocumentSnapshot (FlutterFire)

I'm trying to make changes to a specific field in a DocumentSnapshot, but I cant figure out how to get the update method to work. I can't even find any documentation to help me figure it out.
whatever.data().update("Availability", (newValue) => whatever);
whatever is a documentsnapshot,'Availabilty' is the field I want to update,
and 'newValue' is the value I want to update the field in the fetched object itself and not in Firestore.
The DocumentSnapshot has a reference property which is the DocumentReference of this snapshot.
Then you can update the document like this:
whatever.reference.update({Availability: "NewValue"})
Edit: OP wanted to updated local variable only and not the data in Firestore which can be done by assigning the data to a variable and update it.
var myData = whatever.data()
myData['property'] = 'value'
Try this
whatever.doc().update({
"Availability": newValue,
});
FirebaseFirestore.instance
.collection('YOURCOLLECTION')
.doc(DOCUMENTID)
.update({'Availability': newValue}).then((value) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Success'),
),
);
}).onError((error, stackTrace) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error while updating document'),
),
);
});
YOURCOLLECTION is the name of your collection and DOCUMENTID is your document Id for which you want to update the data.

How to create a Firebase Cloud Function for a Document Created on a Collection inside of another Document and Collection

I have a question with CloudFunctions, I need to create a function on Create of a document inside Firestore.
The problem that I have is the way the data is set up:
So I have a Collection called Chat Rooms which gets documents that will vary, and inside each document, you will have some fields and another subcollection, and inside that subcollection already the thing that I need to get on the function.
The problem that I have is that this function should be aware or access with every document created:
Somehting like:
exports.ChatSent = functions.firestore.document('chatrooms/{Variable part}/chats').onCreate((snap, ctx) => { print('do whatever'); return;});
The problem is I don't know how to write that variable part as this function should be executed whenever a new document is written on the Chats collection of each one of the documents inside the Chatroom collection.
Any Ideas?
You should use twice a wildcard when defining the path, as follows:
exports.ChatSent = functions.firestore.document('chatrooms/{chatroomId}/chats/{chatId}').onCreate((snap, ctx) => {
print('do whatever');
return null;
});
If you need to get the wildcards values, do as follows:
exports.ChatSent = functions.firestore.document('chatrooms/{chatroomId}/chats/{chatId}').onCreate((snap, ctx) => {
const chatroomId = ctx.params.chatroomId;
const chatId = ctx.params.chatId;`
print('do whatever');
return null;
});

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.

Create and update database with input from PageView.builder in flutter

I have a PageView.builder that has a textFormfield and a title. The builder iterates through the elements of the list and once on the last one, there is a submit button that I would like to send the Key : Value pairs to firestore. when I use for each, it only creates the content of the last item of the list multiple times.
here is my create and update function:
Future updateDatabase(String remarkText) async {
return await databaseCollection.document().setData({
questionItems[index].title : questionItems[index].remarkText
});
}
and this is how I call it in my button
onPressed: () async {
questionItems.forEach((question) async {
await updateDatabase(remarkText);
});
},
How can I loop through them to send data for the previous items as well? Please help.
I think it's iterating over all items, but updating always the same item in Firestore. The variable index should be changed in each iteration somehow. Otherwise each iteration will set value on the same questionItems[index].
I hope it will help!

Removing specific map/object from array in firebase

I'm experimenting with arrays and maps/objects in firestore. I wondered how can I remove a specific map from the array.
I tried something like this:
await Firestore.instance.collection('users').document(interestedInID).get().then((val){
return val.data['usersInterested'].removeWhere((item)=>
item['userID'] == userID
);
}).catchError((e){
print(e);
});
but I get this error in terminal:
Unsupported operation: Cannot remove from a fixed-length list
I don't really understand what it means. I did some googling and fixed-length list is exactly what it says. It's a list that has a fixed length and it can't be changed, but fixed-length list has to be declared explicitly. Growable list on the other hand doesn't need to be declared.
I haven't declared the fixed-length list in my firestore, yet it keeps saying that I can't remove elements from it. I can add / push elements however and remove them using:
'key': FieldValue.arrayRemove([value])
but I can't figure out how to remove the element based on a specific condition. In this case an userID.
Any suggestions?
Thanks a lot!
Figured it out.
await Firestore.instance.collection('users').document(interestedInID).updateData({
'usersInterested': FieldValue.arrayRemove([{}.remove(userID)])
});
I'm not sure, but I think get() simply allows you to read the document, but doesn't allow to make any changes to it.
Anyways, now it works
This may be a workaround:
You fetch your specific Array with key: values from Firebase
Put that in a temporary reference List in dart
Remove your specific Map from the reference List, like you did before
Update data in Firebase like so:
// make a reference List
List<Map> _modifiedUsersInterested = List();
// ... (fetch your Array first from Firebase, put those items in the reference List)
// remove the right Map from the reference List
_modifiedUsersInterested.removeWhere((item) => {
item['userID'] == userID
});
// set the reference List as your array in Firebase
await Firestore.instance
.collection('users')
.document(interestedInId)
.updateData(
{'usersInterested': _modifiedUsersInterested}
);

Resources