FieldValue.arrayRemove() is not working with string array - javascript

I am storing the firebase cloud messaging registration tokens for the users in the firestore users collection and whenever I'm sending a notification, I'm deleting the tokens which are unused. I'm doing this on the cloud function with admin sdk. The code I'm using is-
let removeRegistrationTokens = async function (userId: string, tokens: string[]) {
await db.collection('users')
.doc(userId)
.update("tokens",admin.firestore.FieldValue.arrayRemove(tokens)
.catch(logError)
}
But this is not working and no value is being deleted from the array. I checked the tokens array and the value passed is correct. If I simply change the code to
.update("tokens",admin.firestore.FieldValue.arrayRemove(tokens[0])
This is deleting the first element in the array from the tokens array in firestore. As per the documentation it should delete all the elements passed to it in the array.
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. arrayRemove() removes all instances of each given element.
Any help on why could it be happening?

arrayUnion and arrayRemove don't accept array arguments. If you want to pass multiple values, they need to be specified as individual arguments. You could try using the JavaScript spread operator to expand that array into multiple args.
arrayRemove(...tokens)
See also the API documentation for arrayRemove.

Related

How do I implement an index for where and orderBy timestamp?

I have this field for the collection in users with either 2 status of condition1 and condition2. And I also wanted to order this in descending order. I tried it with this but it will display that I first need to create an index.
The status is in string. And the createdAt is in timestamp
const userRef = collection(db, "users");
const q = query(
ordersRef,
where("status", "==", "Condition1"),
orderBy("createdAt", "desc")
);
const querySnapshot = await getDocs(q);
Also, is it necessary to filter this with Firebase or I could just filter using Javascript? However, I would still like to know how I can use indexing here.
If you attempt the query above without first creating the required index, Cloud Firestore returns an error message containing a link you can follow to create the missing index.
This happens any time you attempt a query not supported by an index. You can also define and manage composite indexes which store a sorted mapping of all the documents in a collection, based on an ordered list of fields to index manually by using the console or by using the Firebase CLI.
Cloud Firestore does not automatically create composite indexes like it does for single-field indexes because of the large number of possible field combinations. Instead, Cloud Firestore helps you identify and create required composite indexes as you build your app. Follow the generated link to the Firebase console, review the automatically populated info, and click Create. Indexes can take a few minutes to build, depending on the size of the query.
After you create them, you can see your indexes and their status in the Composite Indexes section. If they're still building, the Firebase console includes a building status bar.

Composite index firestore

I am using two different queries to order my data and putting a where clause. I need a composite index. I am also using limitToLast
const tradesRef = firebase
.firestore()
.collection("trades")
.orderBy("time", "asc")
.where("type", "==", "fiveMinutes")
.limit(15);
I have created a composite index such as:
I am still getting this error:
The fields indexed seem to be correct but you are not running a collection group query so have you tried setting the query scope to just "Collection" instead of "Collection group"?
Also try deleting current index and creating new index directly using the link in error.
As mentioned in the stackoverflow Answer :
Since you're querying on two fields (status and createDate), there
needs to be a composite index on those two fields. Indices on
individual fields are automatically created, but composite indexes are
only created when you ask for them. The error message should contain a
link directly to the console to complete that task. If that's not the
case, you can create it here.
For more information related to how firestore manages indexes, you can refer to the documentation.

Firestore Array of map not updating

So I'm working on a personal project to learn react-native and Firestore.
I have a DB like this:
And I want my code to add a new battery in the array batteries.
The elements in the array are just a map{string, string}
The problem is that when I update the array with a new brand that's work but if I want to update it with the same brand again have,
so having by the end
batteries[0]: {'brand': 'cestmoi'}
batteries[1]: {'brand': 'cestmoi'}
The DB doesn't update, doesn't have any error or so.
I don't understand why and I followed their tutorial. Here is my code:
async function addData(collection, doc, value) {
console.log(`Add data ${value.brand}`)
try {
const result = await firestore()
.collection(collection)
.doc(doc)
.set({
batteries: firestore.FieldValue.arrayUnion(value)
})
console.log(result);
return result;
} catch (error) {
return error;
}
}
I use try-catch by habit but I don't know if the then...catch is better or not.
As already #windowsill mentioned in his answer, there is no way you can add duplicate elements in an array using client-side code. If your application requires that, then you have to read the entire array, add the duplicates and then write the document back to Firestore.
However, if you want to update an existing element in an array of objects (maps) then you have to use arrayUnion with the entire object. If you want to understand the mechanism better, you can read the following article which is called:
How to update an array of objects in Firestore?
arrayUnion says that it "adds elements to an array but only elements not already present". Maybe it does a stringify or something to check equality and therefore doesn't add the new element. I think you'll have to 1. get the current list, 2. add your element, 3. set the batteries field to the updated list.

How can I update an object inside of an array in firestore?

I would like to update the completed property of an object in an array in Firestore, but I have no idea how to reach that specific element in the array. The image will show the structure.
I have come up this far but don't know how to choose, for example, item 1 in the array. I was thinking of using its ID (it has an id property) but don't know how to get there.
const businessRef = db.collection('approvedBusinesses').doc(businessId)
try {
businessRef.update({
[`bookings.${currentDate} ????? `]: true // what to add after currentDate?
})
By the way, this is how the array was created (and how other objects are pushed to it)
const bookingObj = {
carro: 'PASSA_CARRO',
completed: false,
userId: userObject.uid,
}
businessRef.update({
[`bookings.${currentDate}`]: firebase.firestore.FieldValue.arrayUnion(bookingObj),
})
Firestore does not have an operation that allows you to update an existing item in an array by its index.
To update an existing item in the array, you will need to:
Read the entire document into your application.
Modify the item in the array in your application code.
Write back the entire array to the document.
I'm pretty sure this has been asked before, so let me see if there's an answer with an example.
Also see:
How to remove an array element according to an especific key number?
Simple task list ordering - how to save it to Firebase Firestore?
How to update only a single value in an array
How to update an "array of objects" with Firestore?

How to increment a map value in a Firestore array

I have a firestore firebase database , in which I have a collection users
there is an array in the collection and in the array there is a map
in map there is a field qty.. I want to increment that qty value..
using increment doesnt help as the qty is inside a array index
db.collection("users").doc(checkId).update({
myCart: firebase.firestore.FieldValue.arrayUnion({
qty: firebase.firestore.FieldValue.increment(1),
}),
this is the error Output =>
Uncaught (in promise) FirebaseError: Function FieldValue.arrayUnion() called with invalid data. FieldValue.increment() can only be used with update() and set()
My answer below won't work, given that the qty is in an array. The only way to update an item in an array is to read the entire document, update the item in the array, and then write the entire array with the updated item back to the document.
An alternative would be to use a map instead of an array, and then update the qty using the approach outlined in my (old, and non-working) answer below 👇
You need to specify the full path to the field you're trying to update. So I think in your case, that'll be:
db.collection("users").doc(checkId).update({
"myCart.0.qty": firebase.firestore.FieldValue.increment(1)
}),
The field you want to update is embedded in an array. In this case, you can't use FieldValue.increment(), since it's not possible to call out an array element as a named field value.
What you'll have to do instead is read the entire document, modify the field in memory to contain what you want, and update the field back into the document. Also consider using a transaction for this if you need to update to be atomic.
(If the field wasn't part of an array, you could use FieldValue.increment().)
As of today (29-04-2020)... this is tested by me.
Suppose my data structure is like this:
collection: Users
Any document: say jdfhjksdhfw
It has a map like below
map name: UserPageVisits
map fields: field1,field2,field3 etc
Now we can increment the number field in the map like below:
mapname.field1 etc...
That is use the dot operator to access the fields inside the map just like you would do to an object of javascript.
JAVA Code (Android), update the field using transactions so they can complete atomically.
transaction.update(<documentreference object>,"UserPageVisits.field1",FieldValue.increment(1));
I have just pushed a version of my app which uses this concept and it's working.
Kudos !!
My Best Regards
Previous answers helped me as well, but dont forget about the "merge" property!!! Otherwise it will overwrite your entire array, losing other fields.
var myIndex = 0;
const userRef = db.collection('users').doc(checkId);
return userRef.update({
'myCart.${myIndex}.qty': admin.firestore.FieldValue.increment(1)
}, {
merge: true
});

Categories

Resources