Uploading Set<String> gives error in flutter - firebase

Okay, so I'm creating chips tiles that are stored in a Set, but when I try to upload it to firebase I get this error "Unhandled Exception: Invalid argument: Instance of '_CompactLinkedHashSet'"
I isolated the code and simplified it so it looks like this:
...
Set<String> _tags = <String>{};
_tags.add('Test1');
Firestore.instance
.collection('tags')
.document(tagsID)
.setData({
'tags': _tags,
});
...
I've tried debugging it, and I can't get it to upload so is there any other kind of way I can get the data from the set and upload it to Firebase? Another data type I can use that Firebase will accept?

Take a look at the data types that Firestore supports. Sets are not supported. You could convert your set to a JSON string, or to a list:
List<String> tagsList = List<String>.from(_tags);

Adding on to Bryson Thill's answer, if you need to use Sets in your code, I'd recommend you use the toList() method before uploading to Firestore.

I would suggest you following the answer from this question:
Adding an Object to Cloud Firestore using Flutter
And you can basically upload any data you want

Related

Is there a way to determine once a cloud function has finished running - either through looping getDownloadURL or messaging?

I am still getting the hang of Firebase and Cloud functions, but here is what I'm trying to figure out.
The current setup
My app has a cloud function that will take a PDF that has been uploaded into a storage bucket and convert it into PNG. It doesn't destroy the original PDF, so I am left with both files.
The URL for the newly created PNG is then attached to a property on one of our documents in Firestore.
What I am trying to accomplish
I want to be able to upload a new PDF to use as a replacement image. I think I am running into a race condition where the cloud function hasn't finished executing by the time I am trying to call updateDoc() with the new PNG.
On the client side, I have the storageRef returned from the upload method:
uploadFunction(...).then((snapshot) => {
return snapshot.ref
}
I'm saving the result of this function to a variable, and I am trying to pass that into the update method that will adjust the property on my document in Firestore:
const storageRef = await functionThatUploadsPDF(file);
updateDocumentInFirestore(storageRef);
Within updateDocumentInFirestore, I'm trying to navigate to the new reference that should exist once the cloud function has finished, get a download URL, and update that property on my document:
const newImageRef = ref(storageRef.parent, "generatedImage.png");
const newDownloadURL = getDownloadURL(newImageRef).then((url) => {
updateDoc(documentRef, backgroundImage: url);
});
However, I am getting the following error - I believe due to the cloud function having not finished yet:
Firebase Storage: Object 'storage-bucket/generatedImage.png' does not exist. (storage/object-not-found)
My thoughts on potential solutions
I could try to poll the storage for the existence of generatedImage.png until the getDownloadURL call returns an actual URL, but I worry about the amount of calls this would yield.
If there is a way for the cloud function to send a message to let me know that the conversion is finished, I can send a call once for the download URL after receiving said message. However, I can't figure out how to accomplish this.
Efforts so far
I have been pursuing course 1. So far, but have not met any success yet. Scouring through Firebase documentation, I haven't been able to find any supporting resources on how to accomplish 1 or 2. Does anyone have any suggestions - either on my planned courses of action, or a new option that I haven't considered?
You can use this onFinalize trigger to send a message or update a document in Firestore to indicate that the function has finished running. This trigger is triggered whenever a file is created or updated.
onFinalize Sent when a new object (or a new generation of an existing
object) is successfully created in the bucket. This includes copying
or rewriting an existing object. A failed upload does not trigger this
event.
you can also create a promise that resolves when the downloadURL is not null, and use that promise in your updateDocumentInFirestore function. This way, the updateDoc function will only be called once the downloadURL is available.
Additionally, as was mentioned in the comments, you can consider cloud workflow.The exact implementation will depend on your specific use case
You can also check these similar cases
Firebase Storage: Object does not exist
Error: storage/object-not-found when trying to upload large image file
Firebase Storage Put could not get object

Flutter & Firebase: How to populate an array and then later, return all the contents

I have been trying to get arrays working in Firebase, and I am aware that there are a lot of references and discussions about this online, and I have read through all of these and none of it works.
First off, the Firebase side. The structure containing the array and two example strings inside it:
Firebase Structure
collection -> document -> fields
userData profileImages URLs (array)
: https://firebasestorage.googleapis.com/v0/b/app-138804.appspot.com/o/jRwscYWLs1DySLMz7jn5Yo2%2Fprofile%2Fimage_picker4459623138678.jpg?alt=media&token=ec1043b-0120-be3c-8e142417
: https://firebasestorage.googleapis.com/v0/b/app-138804.appspot.com/o/jRwscYWLs3872yhdjn5Yo2%2Fprofile%2Fimage_picker445929873mfd38678.jpg?alt=media&token=ec3213b-0120-be9c-8e112632
The first issue I am facing is writing to this array in the database:
Firestore.instance.collection('userData').document('profileImages').updateData({
'URLs': _uploadedFileURL,
});
Whenever I add data to this array, it just overwrites the existing data. I need to be able to keep all the existing data intact and simply add the current new line to the array.
Once this is working, I then need to be able to return all of the strings in this array without needing to know how many of them there will be.
For this part, I basically have nothing at this point. I could show some of the things I have tried based on suggestions from other articles on this, but none of it is even close to working correctly.
im assuming that _uploadedFileURL is a String, and you are updating the property URLs, that's why your data gets overwritten, because you are changing the URLs value to a single string which is _uploadedFileURL. to solve this issue, simply get the current data inside profileImages before commiting the update. like so
final DocumentSnapshot currentData = await Firestore.instance.collection('userData').document('profileImages').get();
Firestore.instance.collection('userData').document('profileImages').updateData({
'URLs': [
...currentData.data['URLs'],
_uploadedFileURL
],
});
and for the second part of your question, all you need is to query for the profileImages
Future<List<String>> _getProfileImages() {
final document = Firestore.instance.collection('userData').document('profileImages').get();
return document.data['profileImages]
}
the result of the get method will be a DocumentSnapshot, and inside the data property will access the profileImages which is a List<String>.
Ok guys and girls I have worked this out. Part 1: appending data to an array in Firebase.
Firestore.instance.collection('userData').document('profileImages').updateDataupdateData({
'URLs':FieldValue.arrayUnion([_uploadedFileURL]),
});
Where _uploadedFileURL is basically a string, for these purposes. Now I have read that arrayUnion, which is super groovy, is only available in Cloud Firestore, and not the Realtime Database. I use Cloud Firestore so it works for me but if you are having issues this might be why.
Now what is extra groovy about Cloud Firestore is that you can similarly remove an element from the array using:
Firestore.instance.collection('userData').document('profileImages').updateDataupdateData({
'URLs':FieldValue.arrayRemove([_uploadedFileURL]),
});
So how to get this data back out again. A simple way I have found to get that data and chuck it into a local array is like so:
List imageURLlist = [];
DocumentReference document = Firestore.instance.collection('userData').document('profileImages');
DocumentSnapshot snapshot = await document.get();
setState(() {
imageURLlist = snapshot.data['URLs'];
});
From here at least you have the data, can add to it, can remove from it and this can be a platform for you to figure out what you want to do with it.

How to create custom index for firestore query

I need to be able to retrieve some data from my cloud firestore database where certain conditions are met and then order that data but I am unable to get my query to work. I've read that if you simply run the query then your log should provide you a link to automatically create the custom index but unfortunately within my flutter logs or the android studio logcat i'm not getting any links. I know you can create the custom indexes manually in the firebase console so i'm happy to do this but I dont know how I would create the index for this.
firestore.collection('users').where('organisation_id', isEqualTo: _authenticatedUser.organisationId)
.orderBy('first_name').getDocuments()
I just need to know how to create the composite index for this query so that it will work in my app
I was able to get a link in my console log by surrounding the firestore query with a try catch and printing out the platform exception which generated the direct link, thanks to Dougs answer
try {
snapshot = await firestore.collection('users').where(
'organisation_id', isEqualTo: _authenticatedUser.organisationId)
.orderBy('first_name').getDocuments();
} catch(e){
print(e);
}

Retrieve data from firebase in react native

enter image description hereHow to retrieve data from firebase database and how to assign that values to variables in react native
How can I get these two values into variables using simple way.
I think the firebase docs are pretty good and give a good explanation of how to use it.
https://firebase.google.com/docs/database/web/read-and-write
To be short:
once you have specified a reference, ex. let users = firebase.database().ref('users/' + userId), you can read the data either once using the .once() method or add a listener for changes in the data using on().
You receive a snapshot from either of these methods, and need to call snapshot.val() to retrieve the data.
Simply assign the snapshot.val() to a variable declared outside of the reading method, and you're good to go.
You can also reference a simple project I made using React-Native and firebase here: https://github.com/liplylie/rnChallenge

Push AngularFire array directly to Firebase on other location

I have AngularFire array and I want to push the data it holds into a new location in my Firebase Database at some point. I try to do it using the push method of Firebase SDK with no success. It gives me an error:
firebase.push failed first argument contains invalid key ($id) ....
It seems that Firebase doesn't like the dollar signs that AngularFire adds. There are also some $$ in the names of the methods in the sync array.
My question is, what is the proper way to get rid of this $ signs and methods before I push my data?
If you're using AngularFire, try using the .$add instead.
var ref = firebase.database().ref().child('myReference');
var array = $firebaseArray(ref);
array.$add(data)
Here are the docs on it: https://github.com/firebase/angularfire/blob/master/docs/reference.md#addnewdata

Resources