Question
I have a collection named Users with a field named friendEmails which is an array that contains Strings.
I have a document with friendEmails = {joe#gmail.com, dan#gmail.com}, and I want to append newEmails = {mat#gmail.com, sharon#gmail.com} to it.
Problem
The only options I know for this are:
Reading the friendEmails array first, then adding the union of it and newEmails to the document.
Iterating over the elements of newEmails (let's and each iteration doing:
myCurrentDocumentReference.update(FieldValue.arrayUnion, singleStringElement);
(Since FieldValue.arrayUnion only lets me pass comma-separated elements, and all I have is an array of elements).
These two options aren't good since the first requires an unnecessary read operation (unnecessary since FireStore seems to "know" how to append items to arrays), and the second requires many write operations.
The solution I'm looking for
I'd expect Firestore to give me the option to append an entire array, and not just single elements.
Something like this:
ArrayList<String> newEmails = Arrays.asList("mat#gmail.com", "sharon#gmail.com");
void appendNewArray() {
FirebaseFirestore firestore = FirebaseFirestore.getInstance();
firestore.collection("Users").document("userID").update("friendEmails", FieldValue.arrayUnion(newEmails));
}
Am I missing something? Wouldn't this be a sensible operation to expect?
How else could I go about performing this action, without all the unnecessary read/write operations?
Thanks!
You can add multiple items to an array field like this using FieldValue.arrayUnion() as the value of a field update:
docRef.update("friendEmails", FieldValue.arrayUnion(email1, email2));
If you need to convert an ArrayList to an array for use with varargs arguments:
docRef.update("friendEmails", FieldValue.arrayUnion(
newEmails.toArray(new String[newEmails.size()])
));
Related
Referring to "Update elements in an array:
I can understand how to add elements to an existing array. But I would like to create a new array if doesn't already exist and then add data to it in a single Firestore call. How to do that?
Doesn't add data if an array is not present.
.update("arrayName", FieldValue.arrayUnion("arrayData"))
Creates a new array if not present and adds data, but the data is overwritten not appended.
.set(hashMapOf("arrayName" to arrayListOf("arrayData")), SetOptions.merge())
I want to make a single Firestore call,
Which checks if an array is present if not creates a new array.
Then it checks if the data is present in the array if not adds the data to the array.
Is there a straightforward solution to this or do we have to make more than one call to achieve this?
Edit:
The code I am using:
return firebaseFirestore
.collection("collection1")
.document("document1")
.collection("collection2")
.document("document2")
.update("arrayName", FieldValue.arrayUnion("arrayData"))
#Alex as you pointed out, the array is created if not present, and data is added to it.
Found my problem to be caused due to a different issue.
In my scenario, the "collection1", "document1", "collection2" and "document2" were not already created. My code works only if the document to which the array is to be added ("document") is already created.
Can you help me in solving this?
Doesn't add data if an array is not present.
Yes, it does. According to the official documentation regarding FieldValue's arrayUnion() method:
Returns a special value that can be used with set() or update() that tells the server to union the given elements with any array value that already exists on the server. Each specified element that doesn't already exist in the array will be added to the end. If the field being modified is not already an array it will be overwritten with an array containing exactly the specified elements.
In other words, if your arrayName property is not an array, your arrayData will be added to an array and then that array will be overwritten in the document. So if your arrayName is not an array, it will become an array. If the property does not exist at all, a new array will be created and it will be added to the document. So if your document looks like this:
Firestore-root
|
--- firstCollection
|
--- firstDocument
|
--- docName: "Doc Name"
After using these lines of code:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
DocumentReference docRef = rootRef.collection("firstCollection").document("firstCollection");
docRef.update("arrayName", FieldValue.arrayUnion("arrayData"));
Your document will look like this:
Firestore-root
|
--- firstCollection
|
--- firstDocument
|
--- docName: "Doc Name"
|
--- arrayName: ["arrayData"]
Edit:
My code works only if the document to which the array is to be added ("document") is already created.
Yes, that's the expected behavior. You cannot update an array in a document that does not exist. To solve this, you should basically create that document, with at least a property so it exists at that particular location. The property might be an empty array or any other supported data-type, as it will be converted later into an array.
A more appropriate solution might be to check if the document exists. If it exists, add it with the desired array, otherwise, update it. But there is no way you can do that in a single go.
I am new in android development and when I read array data from firestore using following code
val variable = arrayOf(document.get("restaurant"))
and then loop over the variable using code
varibale.forEach {
Log.d("someTag", ${it.toString()} + " is your data")
}
I get the result with square brackets at log as following
[somedata, somedata2] is your data
my problem is that forEach loop runs only once and I am not able to get the result (without square brackets) as following
somedata is your data
somedata2 is your data
I have 2 elements in my restaurant array in firestore
I will be very thankfull to any one who will help me.
You are actually wrapping an array/list into another array when using arrayOf, that's why you see those brackets. Instead, try casting your document.get("restaurant") and then looping directly through it.
arrayOf doesn't parse an array. It creates a new array using the elements you pass to it. That's not what you want. You should instead cast document.get("restaurant") to the type that you expect to get from Firestore.
If a field is an array of strings, then the SDK will give you a List<*>, and you will need to make sure each item in the list is a String, if that's what you stored in the array.
val variable = document.get("restaurant") as List<*>
// Iterate variable here, make sure to check or convert items to strings
My Firebase database contains 2 collections of name "collectionA" and "collectionB", and they both contain different documents. They both have rules to allow authenticated users to read and write (however I don't get permission erros anyway). The problem is when I get a reference to collectionA and B as such:
var docRefA = db.collection("collectionA")
var docRefB = db.collection("collectionB")
Collection A retrieves docs with its respective documents, but collection B returns empty docs. I can still write to collection B succesfully though, so I know the docRef isn't wrong. I'll attach an image of the actual collections in case there is any differences between the collections I'm not aware of:
collection A and B - "users" collection would be collectionA and "store_exercises" would be B. The only difference I see is the documents in B are greyed out and italic, not sure what this could mean?
EDIT 1: This is how I generate/add items to collection A (I can see both write operations work, it's only reading):
val userMap = HashMap<String, String>()
userMap["username"] = username
userMap["email"] = email
db.collection("users").document(auth.currentUser!!.uid).set(userMap)
and collection B:
db.collection("store_exercises").document("whatever").collection("another_collection").document("name")
.set(myObject)
EDIT 2: Image of contents of the two collections:
contents of both collections
Else, how can I debug a query? or test this scenario?
Ok, just figured that one out, if a document doesn't contain fields, and just collections (even if those collections are composed of non empty documents), then it will think its an "empty branch" and not display anything chained in there.
I only wanted 2 collections so I had to create a document to link them so I didn't add any fields, but unless there's some notation or something it seems like adding at least one field is a must for them to be read. All I did was add one field to the documents in collection B, and now they're not empty.
How to make history score in Array
I try u make score in array like this
this my firestore
And this is my code
String uid = auth.getCurrentUser().getUid();
muridref.document(uid).update("nilai", FieldValue.arrayUnion(skortampil));
When I get the same score the array field doesn't make new Array data,
without see data there or not in array
As mentioned in the documentation Update elements in an array about this behavior:
If your document contains an array field, you can use arrayUnion() and arrayRemove() to add and remove elements. arrayUnion() adds elements to an array but only elements not already present.
Considering that, it's working as expected, since it's not adding values that are equal. So, this means that you won't be able to add values that are equal using the method arrayUnion() directly.
This other question from the Community - accessible here - indicates that for you to achieve this goal, you will need to read all the values from the array in your client side, update your values in the array outside the database and then, writing/updating it back in the database.
Let me know if the information helped you!
E.g. I have next data in my Firebase Realtime Database (my json file contains json array of some objects):
I would like to get all objects starting from a specific index (position) to the end of this array (in Firebase DB json array is converted to simple object which contains children with keys 001, 002 and so on)
So I need something like this but for Firebase query:
list.subList(10, list.size)
I know there are limitToFirst, limitToLast methods but it's different
fireDatabaseReference.child("episodes").limitToLast(10)
It won't do what I need. Because I need to know the size of this array and I need to be sure that this array won't become bigger at the moment someone makes such request (at some point this array can get become bigger due to adding new objects)
Would be great to have a method like from to get all children from 10 to the end (so first 9 children are excluded):
fireDatabaseReference.child("episodes").from(10)
But there is no such method
Is there any solution for this?
Solved :)
fireDatabaseReference.child("episodes").orderByKey().startAt("10")