【问题标题】:How to query the existing children of a sibling node and loop over them to detect if it exists?如何查询兄弟节点的现有子节点并遍历它们以检测它是否存在?
【发布时间】:2018-10-18 11:04:39
【问题描述】:

我正在尝试在 firebase 数据库中更新(添加)新的子节点。在这种情况下,我正在更新两个节点 and_"door/{MACaddress_1}/ins"_ & _"doors/{MACaddress_2}/ins"_ 并且这两个节点都需要通过 Google Cloud 函数写入名为 “房间/{roomPushKey}/ins”。

我将通过物联网设备上的 Arduino 程序更新初始 “门” 节点,该设备具有连接到数据库的唯一 MAC 地址到 '/doors/' + {MAC 地址} + '/ins'。

这些是基本条件:

1) 如果 "rooms/{roomPushKey}/ins" 尚未创建,则创建它(防止写入第一个数据时出现未定义或空错误情况)。

2) 两个“门” 通常都有不同的子键。所以我不能简单地覆盖兄弟 "room" 节点的数据,因为这会删除未更新的一扇门的节点。这里我需要确保 "rooms/{roomPushKey}/ins" 只从每个 获取新数据。 p>

3) 我需要检测写入的新数据是否已在兄弟 "rooms/{roomPushKey}/ins" 节点上不存在,因为有时 *doors* 将具有相同的密钥,当发生这种情况时,云函数需要为正在写入的第二个密钥添加后缀“_a”。

假设这是我的初始数据结构。

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,
          1525104150000: true // Trouble! this key is also on the other door
       }
    },
    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:
          1525104151220: true,
          1525104151440: true,
          1525104150000: true // Trouble! this key is also on the other door
       }
    }
  },
  rooms: {
    -LBMH_8KHf_N9CvLqhzU: {
      ins: {
        // I want the function to clone the same data here:
        1525104151100: true,
        1525104151183: true,
        1525104151220: true,
        1525104151440: true,
        1525104150000: true, // this key is on both doors 
        1525104150000_a: true, // so a suffix must be added 
      }
    }
  }

上周我从 Renaud Tarnec 那里得到了很多帮助,但我认为我的问题表述得不够好。

这就是 Google Cloud 功能的当前状态:

// UPDATING ROOMS INS/OUTS

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; // defining an object in the Rooms/{roomPushKey}/ins node to check what data is already there

        const updates = {}; // defining an empty updates object to populate depending on the scenario
        // avoiding the null/undefined error the first time data is written: all good here!
        if (insBefore === null || insBefore === undefined ) { 
            Object.keys(insAfter).forEach(key => {
            updates['/rooms/' + roomPushKey + '/ins/' + key] = true;
            });
        } else {
            // problem!
            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);
    });
});

这是克隆数据库中已经存在的所有数据(不是最近的新密钥:对)。 例如,如果将 "1999999999999: true" 中的“key:pair”添加到这样的数据库中:

rooms: {
    -LBMH_8KHf_N9CvLqhzU: {
      ins: {

        1525104151100: true,
        1525104151183: true,
        1525104151220: true,
        1525104151440: true,
        1525104150000: true,
      }
    }
  }

我最终得到一个 "rooms/{roomPushKey}/ins",看起来像这样:

rooms: {
    -LBMH_8KHf_N9CvLqhzU: {
      ins: {
        // I want the function to clone the same data here:
        1525104151100: true,
        1525104151183: true,
        1525104151220: true,
        1525104151440: true,
        1525104150000: true,
        1525104151100_a: true,
        1525104151183_a: true,
        1525104151220_a: true,
        1525104151440_a: true,
        1525104150000_a: true, 
        1999999999999: true // this last one isn't cloned but all the previous data in the database is
      }
    }
  }

什么时候应该这样写:

  rooms: {
    -LBMH_8KHf_N9CvLqhzU: {
      ins: {

        1525104151100: true,
        1525104151183: true,
        1525104151220: true,
        1525104151440: true,
        1525104150000: true,
        1999999999999: true
      }
    }
  }

如果另一扇门写“1999999999999: true”,它应该只将“_a”添加到最后一个节点:

  rooms: {
    -LBMH_8KHf_N9CvLqhzU: {
      ins: {

        1525104151100: true,
        1525104151183: true,
        1525104151220: true,
        1525104151440: true,
        1525104150000: true,
        1999999999999: true,
        1999999999999_a: true,

      }
    }
  }

我需要克隆 last "key:pair" 添加到 "doors/{MACaddress}/ins" if em>last "key:pair" 已经在 _"rooms/{roomPushKey}/ins"_ 节点中,忽略所有 "doors/{ 中已经存在的 "key:pairs" MACaddress}/ins" 个节点。

类似这样的:

有什么想法吗?

【问题讨论】:

  • 对象没有顺序,所以 "last" 不能保证它是最后添加的。应该为此使用时间戳
  • 谢谢@charlietfl。是的,我正在编写时间戳,但有 0.01% 的机会同时编写两个时间戳。发生这种情况时,函数将具有不同的执行时间(这将允许我在最后一个检查数据库的函数中添加后缀)。这就是我开发这个功能的原因。
  • 我正在物联网设备上运行一个 Arduino 程序,该设备具有一个唯一的 MAC 地址,该地址将数据库连接到“/doors/”+{MAC 地址}+“/ins”。有一个传感器可以做到这一点。
  • @JoaoAlvesMarrucho 您能否强调一下我们上周制定的解决方案中什么不起作用(或应该以不同的方式起作用)?
  • @JoaoAlvesMarrucho 我看到你想出了几个解决方案,一个是 Renaud Tarnec 提出的,另一个是你发现的(更有效)。请您将它们都发布为答案吗?只是为了保持论坛有序和有用。

标签: javascript firebase firebase-realtime-database google-cloud-functions


【解决方案1】:

这个问题源于两种不同的方法。请在此处找到它们:

1) Renaud Tarnec 使用云功能

这应该可以,但我还没有测试过。您可能需要测试 insBefore is undefined 除了测试它是否为空。我让你微调。

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

});

2) 第二种方法更直接

我决定在 Arduino 程序上解决它,因为所有门都有不同的 MAC 地址,我只是将 MAC 地址添加到时间戳的末尾,因为没有门会同时注册两个 ins为了我。

【讨论】:

  • 完美,非常感谢!几天后您将能够接受答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多