update object in array - Firebase functions - firebase

Function executes when a write is made in collection logs, it checks if doc exists in collection totals. If doc exists it is trying to update number object with number+1 at [0] of array.
Here is my code:
...//some code
var washingtonRef = admin.firestore().collection('totals').doc(entryDate_show);
washingtonRef.get().then((doc: any)=> {
if (doc.exists) {
console.log("doc found");
console.log("Document data:", doc.data());
washingtonRef.update({
[auth_ID]: admin.firestore.FieldValue.arrayUnion(
{ number: doc.data().number+1, // here it is trying to do +1
fullname: fullname,
authid: auth_ID },
)
});
...//some code
Problem: It is not working as expected
In array, it is adding new object [1] with number : NaN
Expected behaviour: number : 2 at [0]
Attaching pic of the console:

FieldValue.arrayUnion() adds a new element to an array field. That's why you're seeing a new object.
Firestore provides no update operation that uses the index of an array item to modify it. If you want to update an item in an array by index, you have to read the document, modify the array in memory, then update the array field back to the document.

Related

Firebase: Removing an Object from an Array

i'm trying to delete an specific object from an array in Firestore via SwiftUI. The following function deletes the whole watchlist. What am I missing?
func removeFromWatchlist() {
if let uid = Auth.auth().currentUser?.uid {
let docRef = db.collection("user").document(uid) // company.symbol = "AAPL"
docRef.updateData(["watchlist": FieldValue.arrayRemove([company.symbol])]) { error in
if error == nil {
print("Successful deleted array")
}
}
}
}
And here is my Firestore structure:
To remove an item from an array with FieldValue.arrayRemove you must specify the exact, complete data that is stored in the array.
Assuming your company.symbol is AAPL, the call FieldValue.arrayRemove([company.symbol] removes that exact string from the array - not the AAPL key that you have with an object under it.
You'll have to read the entire array from the document into you application code, remove it there, and then write the entire modified array back to the document.

Error: 3 INVALID_ARGUMENT: Cannot convert an array value in an array value

I would like to do a batch update for my field which has an array type. My code is as shown below (using typescript for firebase cloud function for this case):
const channelRefs = await admin.firestore().collection("channels").where("participants", "array-contains", AA).get();
const batch = admin.firestore().batch();
channelRefs.docs.forEach((doc) => {
const channelDocRef = admin.firestore().collection("channels").doc(channelID);
batch.update(channelDocRef, {"photoURL":[xx, yy]});
}
await batch.commit();
But there is an error message in the logs as shown:
Error: 3 INVALID_ARGUMENT: Cannot convert an array value in an array
value.
I think the likely cause of the error is the code where I update the array which is
batch.update(channelDocRef, {"photoURL":[xx, yy]});
Any suggestion on an array field with a new set of data? Thanks
---edit below----
My data is as shown below:
User
—Photo(array)
—photo1(string)
—photo2(string)
What I want is to replace photo1 with something else so what I did was to just replace the whole array with
db.collection("users").doc(doc.id).update({photo: [photo3,photo1]});
since I can't simply replace the first item in the array

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;
});

How to query an array of objects in a Firebase Cloud Function, to get a matching object and then update

I am using a scheduled task in a Firebase Cloud Function to query an array which contains a number of objects that need to be updated if a matching condition exists. My current attempt is using the 'array-contains' method to get the objects, then loop over them to find a matching condition which will then batch update the items. This is my data structure:
I need to find an object that is <= the current time, and also if the 'active' value = false.
export const liveMeetingsTrigger = functions.runWith( { memory: '1GB' }).pubsub
.schedule('every 1 minutes').onRun(async context => {
const now = admin.firestore.Timestamp.now();
const liveMeetings = await admin.firestore().collection('fl_content').where('meeting', 'array-contains', 'liveMeetingDate').get();
const batch = admin.firestore().batch();
liveMeetings.forEach(doc => {
if(doc.data().liveMeetingDate <= now && doc.data().active == false){
batch.update(doc.ref,'active',true);
}
});
return await batch.commit();
});
I have also tried using an exact object in the query instead of just using 'liveMeetingDate', but still get no results back, any help would be great - thanks.
Debugging: As the array I am trying to reach is inside of the (map) object 'liveMeetings' i have tried the dot notation (liveMeetings.meeting) with no success. Also trying a new collection with the the 'meeting' array at top level has provided no success.
Simple logging in the console (liveMeetings.size) shows that nothing is being returned on the query, so therefore the logging does not even reach the loop in the code.
As explained in this anwser the following query will not work:
const liveMeetings = await admin.firestore().collection('fl_content').where('meeting', 'array-contains', 'liveMeetingDate').get();
because the meetings array contain some objects, instead of "simple" or primitive data (e.g. string, number...).
You could query it with the exact objects, like:
const obj = {active: false, liveMeetingDate: ..., meetingId: ..., ....};
const liveMeetings = await admin.firestore().collection('fl_content').where('meeting', 'array-contains', 'obj').get();
Another approach would be to create a new collection which contains the similar documents (same Document ID) but with a meeting Array that contains only the liveMeetingDate property.
Finally, note that since your Array is within a map, you need to do
await admin.firestore().collection('fl_content').where('liveMeetings.meeting', 'array-contains', ...).get();
(PS: I don't mark this question as duplicate since you expressly ask for more help in the comments of the duplicate question/answer)

How to create collections in cloud firestore dynamically from cloud functions

I am trying to create collections and sub collections for document inside a collection dynamically from cloud functions,
But I am getting following exception
**
Argument "collectionPath" must point to a collection, but was
"data/c2f7c4e84366". Your path does not contain an odd number of
components
**
Logs -
Error: Argument "documentPath" must point to a document, but was "exports/user343434_inbox/profile". Your path does not contain an even number of components.
at Firestore.doc (/user_code/node_modules/firebase-admin/node_modules/#google-cloud/firestore/src/index.js:282:13)
at admin.firestore.doc.set.then.ws (/user_code/lib/index.js:28:53)
code snippet:
const p = admin.firestore().doc(exports/${userInboxCollectionName}/profile).set(reqData, { merge: false })
*
I am expecting cloud function to create the subcollection(userid_inbox) inside exports collection(already exists) dynamically if not exists and add the profile document.
Firestore works like this: collection / document / subCollection / "subDocument" / and so on.
You should try: (I'm using TS)
let p = admin.firestore().collection(`exports/${userUID}/${theSubcollection}`)
.add({ message: messageString })
.then(ref => {
console.log('Added document with ID: ', ref.id)
});
//let's see the estructure here:
//collection.......exports
//document.........${userUID}
//subcollection....${theSubcollection}
//document.........ref.id
//data.............message with value messageString
with this code you are creating an new document with the value message on a new subcollection.

Resources