shruti tupkari
shruti tupkari

Reputation: 1429

Error while saving JSON data to Firestore collection using cloud function

I am trying to insert array in my firebase collection from cloud function. I need to have multiple lines in one document so for each line i am inserting an array. Please check my attached screenshot where you can see line0 , same way i need to have Line1,Line2,Line3..,Line n in the same document.

for line0 i am passing array from code like below and its working fine.

admin.firestore().collection("qbContestWinners").add(
        {
            'cmpientryid': context.params.processId,
            'qbid': '',
            'qbsyncdate': '',
            'qbsyncstatus': 'pending',
            'Line0':
            {
                id: "0",
                description: 'PRIZE AMOUNT',
                amount: 1000,
                accountrefid: contestresultData.qbcontestid,
                accountrefname: contestresultData.qbcontestname,
                contestresultId: context.params.processId,
            },
        })

when i am looping through data i am getting from another table , i am not able to generate proper JSON to insert.

below is how i am looping and creating JSON after getting data from another table.

   i = 1;
            admin.firestore().collection("results").where('cid', '==', 'LKRRk2XXXXXXXX')
            .orderBy("rank", "asc").get().then(snapshots =>
                        {
                            snapshots.forEach(doc =>
                                {
                                    const contestresultId = doc.id;
                                    const prizeAmount = doc.data().prizeamt;
                                    const userId = doc.data().userid;
                                    const lineNum = "Line" +  i;
                                    console.log("new line numner is: ", lineNum);
                                    console.log(`lineNum? ${lineNum}`);

                                    const linetxt = "Line" + String(i);
                                    const insertData = "{"+linetxt +
                                                        ":{id:'" + i +
                                                         "', description: 'PRIZE AMOUNT'"+
                                                           ", amount:" + prizeAmount + "," +
                                                           "accountrefid:"+ contestresultData.qbcontestid +","+
                                                           "accountrefname:'" +contestresultData.qbcontestname +"',"+
                                                           "contestresultId:'" + contestresultId +"'," +
                                                       "},}"
                                      const finalInsert = JSON.stringify(insertData);
                                      const finalJSON = JSON.parse(finalInsert);
                                       admin.firestore().collection("qbContestWinners").doc(mainID).set(

                                         finalInsert.toJSON(),

                                    {
                                        merge: true
                                    });

                                i= i+1;
                            });
            });

using this code i am getting error finalInsert.toJSON is not a function enter image description here

Upvotes: 0

Views: 472

Answers (2)

Renaud Tarnec
Renaud Tarnec

Reputation: 83103

Actually, the Line0 field is a map and not an Array, see this doc for more details.

So, if you want to create similar fields (Line1, Line2, ...), you simply need to pass a JavaScript Object to the set() method, as follows:

snapshots.forEach(doc => {
        const contestresultId = doc.id;
        const prizeAmount = doc.data().prizeamt;
        const userId = doc.data().userid;
        const lineNum = "Line" +  i;
        console.log("new line numner is: ", lineNum);
        console.log(`lineNum? ${lineNum}`);

        const lineObj = {
            id: i,
            description: 'PRIZE AMOUNT',
            accountrefid: contestresultData.qbcontestid,   //Not sure if you have defined contestresultData somewhere...
            //...
        }

        const dataObj = {};
        dataObj["Line" + i] = lineObj   // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors

        admin.firestore().collection("qbContestWinners").doc(mainID).set(dataObj, {merge: true});

        i= i+1;
});

HOWEVER, note that you must return a promise that resolves when all the asynchronous work in your Cloud Function is complete (i.e. call to the Firestore set() method).

This is explained in the official Firebase video series, watch in particular the three videos titled "Learn JavaScript Promises".

Since you are calling several times the set() method in a forEach loop, you need to use Promise.all() in order to return a Promise when all these parallel calls to the set() method are completed.

The following should do the trick:

let i = 1;
return admin.firestore().collection("results")    // <-- See the return here
.where('cid', '==', 'LKRRk2XXXXXXXX')
.orderBy("rank", "asc").get()
.then(snapshots => {
    const promises = [];

    snapshots.forEach(doc => {
            const contestresultId = doc.id;
            const prizeAmount = doc.data().prizeamt;
            const userId = doc.data().userid;
            const lineNum = "Line" +  i;


            const lineObj = {
                id: i,
                description: 'PRIZE AMOUNT',
                accountrefid: contestresultData.qbcontestid,
                //...
            }

            const dataObj = {};
            dataObj[lineNum] = lineObj;

            promises.push(admin.firestore().collection("qbContestWinners").doc(mainID).set(dataObj, {merge: true}));

        i= i+1;
    });

    return Promise.all(promises)  // <-- See the return here
});

A last remark: if mainID keeps the same value in the snapshots.forEach loop, you may adopt a totally different approach, consisting in building a JavaScript object with several LineXX properties and call the set() method only once. Since you didn't share the entire code of your Cloud Function it is impossible to say if this approach should be used or not.

Upvotes: 2

Naxmefy
Naxmefy

Reputation: 41

first to the error

You stringify and parse a string. The problem here seems to be the order. You have to parse a "String" and to stringify an "Object". The result won't have a toJSON Method as well, but u can just stringify the Object to get a json.

the second thing

Why do you use a string to create your object? You shouldn't. Just use an object.

the third thing

You should not use Objects as Arrays. Not even in firebase.

Just use arrays. Example:

[Line0Object, Line1Object, ...]

Hint: If your array can work as its own collection. Just use a SubCollection. This might fit your needs.

Upvotes: 0

Related Questions