如何使用 Google Cloud Function 查询现有子代并遍历 Object 以检测它是否存在于 Firebase 中?

人气:957 发布:2022-10-16 标签: javascript foreach object firebase google-cloud-functions

问题描述

我正在尝试在 firebase 数据库中更新(添加)一些子项.在这种情况下,我需要使用更新对象更新节点而不用 Google Cloud Function 覆盖所有子节点.

I am trying to update (adding) some children on a firebase database. On this scenario I need to update a node without overwriting all the child nodes with Google Cloud Function using an update Object.

这个问题来自这个问题:如何使用更新对象更新节点而不用 Google Cloud Function 覆盖所有子节点?

This question derives from this one here: How to update a node without overwriting all the child nodes with Google Cloud Function using a update Object?

我的数据结构是这样的:

My data structure is like this:

root: { 
  doors: {
    111111111111: {
       MACaddress: "111111111111",
       inRoom: "-LBMH_8KHf_N9CvLqhzU", // I will need this value for the clone's path
       ins: {
          // I am creating several "key: pair"s here, something like:
          1525104151100: true,
          1525104151183: true,
       }
    },
    222222222222: {
       MACaddress: "222222222222",
       inRoom: "-LBMH_8KHf_N9CvLqhzU", // I will need this value for the clone's path
       ins: {
          // I am creating several "key: pair"s here, something like:
          2525104157710: true,
          2525104157711: true,
       }
    }
  },
  rooms: {
    -LBMH_8KHf_N9CvLqhzU: {
      ins: {
        // I want the function to clone the same data here:
        1525104151100: true,
        1525104151183: true,
      }
    }
  }

我正在尝试查询现有的ins"并在对象上循环以在添加它们之前检测它是否存在,这样我就可以在键中添加后缀以防它们已经存在.这是我的功能.

I am trying to to query the existing "ins" and loop over the object to detect if it exists before I add them so I can add a suffix to the key in case they are already there. This is my function ate the moment.

 exports.updateBuildingsOuts = functions.database.ref('/doors/{MACaddress}').onWrite((change, context) => {
    const afterData = change.after.val(); // data after the write

    const roomPushKey = afterData.inRoom;
    const ins = afterData.ins;

    const updates = {};
    // forEach loop to update the keys individually
    Object.keys(ins).forEach(key => {
            parentPath =  ['/rooms/' + roomPushKey + '/ins/']; // defining the path where I want to check if the data exists
            // querying the "ins"
            admin.database().ref().parentPath.on('value', function(snapshot) {
                if (snapshot.hasChild(key)) {
                    updates['/rooms/' + roomPushKey + '/ins/' + key + "_a"] = true; // define 'updates' Object adding a suffix "_a"

                    return admin.database().ref().update(updates); // do the update adding the suffix "_a"

                } else {
                    updates['/rooms/' + roomPushKey + '/ins/' + key] = true; // define update Object without suffix

                    return admin.database().ref().update(updates); // do the 'updates' without suffix
                }
              });
        });   

此云函数正在检索错误:

This cloud function is retrieving an Error:

TypeError:无法读取未定义的属性on"在 Object.keys.forEach.key

TypeError: Cannot read property 'on' of undefined at Object.keys.forEach.key

我确信我过于复杂了,但我无法为此找到更清晰的逻辑.

I am sure I overcomplicating but I haven't been able to find a cleaner logic for this.

您对如何精益求精有什么建议吗?可能吗?

Would you have any suggestions on how to do this leanly? Is it possible?

推荐答案

你可以这样做:

let afterIns;
exports.updateRoom = functions.database.ref('/doors/{MACaddress}').onWrite((change, context) => {

    const beforeData = change.before.val();  //data before
    const insBefore = beforeData.ins;

    const afterData = change.after.val(); // data after the write
    const roomPushKey = afterData.inRoom;
    afterIns = afterData.ins;

    return admin.database().ref().update(updates);

    const updates = {};

    Object.keys(ins).forEach(key => {
        if (insBefore.hasOwnProperty(key)) { // checking if the insBefore object has a key equal to value 'key'
            //True -> add an extra character at the existing key
            updates['/rooms/' + roomPushKey + '/ins/' + key + '_a'] = true;  //<- _a being the extra character
        } else {
            updates['/rooms/' + roomPushKey + '/ins/' + key] = true;
        }
    });

    return admin.database().ref().update(updates);

}).catch(error => {
    console.log(error);
    //+ other error treatment if necessary

});

不要忘记函数返回change.before.val();之前的数据(除了之后的数据),因此你不必做admin.database().ref().parentPath.on('value', function(snapshot) {

Don't forget the function returns the data before change.before.val(); (in addition to the data after), therefore you don't have to do admin.database().ref().parentPath.on('value', function(snapshot) {

评论后编辑

这应该可以,但我还没有测试过.您可能需要测试 insBefore 除了测试它是否为空之外未定义.我让你微调.

This should work, but I haven't test it. You may need to test is insBefore is undefined in addition to testing it is null. I let you fine tune it.

let insAfter;
let roomPushKey ;
exports.updateRoomIns = functions.database.ref('/doors/{MACaddress}').onWrite((change, context) => {
    const afterData = change.after.val(); // data after the write
    roomPushKey = afterData.inRoom;
    insAfter = afterData.ins;
    return admin.database().ref('/rooms/' + roomPushKey).once('value').then(snapshot => {
    const insBefore = snapshot.val().ins;
    const updates = {};
    if (insBefore === null || insBefore === undefined ) {
        Object.keys(insAfter).forEach(key => {
           updates['/rooms/' + roomPushKey + '/ins/' + key] = true;
        });
    } else {
        Object.keys(insAfter).forEach(key => {
           if (insBefore.hasOwnProperty(key)) {
              updates['/rooms/' + roomPushKey + '/ins/' + key + '_a'] = true; 
           } else {
              updates['/rooms/' + roomPushKey + '/ins/' + key] = true;
           }
        });
    }
    return admin.database().ref().update(updates);
    });
});.catch(error => {
    console.log(error);
    //+ other error treatment if necessary

});

892