简体   繁体   English

使用云功能将 JSON 数据保存到 Firestore 集合时出错

[英]Error while saving JSON data to Firestore collection using cloud function

I am trying to insert array in my firebase collection from cloud function.我正在尝试通过云函数在我的 firebase 集合中插入数组。 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.请检查我附加的屏幕截图,您可以在其中看到 line0 ,与我需要在同一文档中包含 Line1,Line2,Line3..,Line n 的方式相同。

for line0 i am passing array from code like below and its working fine.对于 line0,我正在从如下代码传递数组,并且它工作正常。

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.当我循环遍历从另一个表获取的数据时,我无法生成正确的 JSON 以进行插入。

below is how i am looping and creating JSON after getting data from another table.下面是我在从另一个表获取数据后循环和创建 JSON 的方式。

   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使用此代码我收到错误finalInsert.toJSON is not a function 在此处输入图片说明

Actually, the Line0 field is a map and not an Array, see this doc for more details.实际上, Line0字段是地图而不是数组,有关更多详细信息,请参阅此文档

So, if you want to create similar fields ( Line1 , Line2 , ...), you simply need to pass a JavaScript Object to the set() method, as follows:因此,如果您想创建类似的字段( Line1Line2 、...),您只需将一个 JavaScript 对象传递给set()方法,如下所示:

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 (ie call to the Firestore set() method).但是,请注意,当 Cloud Function 中的所有异步工作完成(即调用 Firestore set()方法)时,您必须返回一个可解决的承诺。

This is explained in the official Firebase video series , watch in particular the three videos titled "Learn JavaScript Promises".这在 Firebase 官方视频系列中进行了解释,特别是观看标题为“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.由于您在forEach循环中多次调用set()方法,因此您需要使用Promise.all()以便在对set()方法的所有这些并行调用完成后返回一个 Promise。

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.最后一点:如果mainIDsnapshots.forEach循环中保持相同的值,您可以采用完全不同的方法,包括构建一个具有多个LineXX属性的 JavaScript 对象,并且只调用一次set()方法。 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.由于您没有共享 Cloud Function 的整个代码,因此无法确定是否应该使用这种方法。

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.结果也不会有 toJSON 方法,但是您可以将对象字符串化以获取 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.这可能符合您的需求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM