0

I am trying to update (adding) new children on a firebase database. On this scenario I am updating two nodes and_"door/{MACaddress_1}/ins"_ & _"doors/{MACaddress_2}/ins"_ and both of this nodes need to write through a Google Cloud function to a sibling node called "rooms/{roomPushKey}/ins".

I will be updating the initial "doors" nodes through an Arduino program on a IoT device with a unique MAC Address that is connecting to the database to the '/doors/' + {MAC Address} + '/ins'.

These are the essential conditions:

1) If the "rooms/{roomPushKey}/ins" is not created yet, then create it (preventing an undefined or null error scenario when the first data is written).

2) Both "doors" normally have different child keys. So I can't simply overwrite the data of the sibling "room" node because that would delete the nodes of the one door that wasn't being updated. Here I need to make sure the "rooms/{roomPushKey}/ins" only gets the new data from each of the doors.

3) I need detect if that new data written doesn't exist already on the sibling "rooms/{roomPushKey}/ins" node because sometimes both *doors* will have the same key, and when that happens the cloud function needs to add a suffix "_a" to the second key being written.

Lets say this my initial data structure.

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

I got a lot of help from Renaud Tarnec last week but I don't think I phrased my question well enough.

So this is the current state of the Google Cloud function:

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

This is cloning all the data that was already present in the database (not the most recent new key:pair). Example, if add a "key:pair" in such as "1999999999999: true" to a database like this:

rooms: { -LBMH_8KHf_N9CvLqhzU: { ins: { 1525104151100: true, 1525104151183: true, 1525104151220: true, 1525104151440: true, 1525104150000: true, } } } 

I am ending up with a "rooms/{roomPushKey}/ins" that looks like this:

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

When it should write this:

 rooms: { -LBMH_8KHf_N9CvLqhzU: { ins: { 1525104151100: true, 1525104151183: true, 1525104151220: true, 1525104151440: true, 1525104150000: true, 1999999999999: true } } } 

And then if the other door writes "1999999999999: true" it should only add the "_a" to the this last node:

 rooms: { -LBMH_8KHf_N9CvLqhzU: { ins: { 1525104151100: true, 1525104151183: true, 1525104151220: true, 1525104151440: true, 1525104150000: true, 1999999999999: true, 1999999999999_a: true, } } } 

I need to clone the last "key:pair" added to the "doors/{MACaddress}/ins" if that last "key:pair" is already in the _"rooms/{roomPushKey}/ins"_ node, and neglect all the "key:pairs" that were already in both "doors/{MACaddress}/ins" nodes.

Something like this:

enter image description here

Any thoughts?

13
  • 1
    Objects don't have order so "last" can't be guaranteed it is last one added. Should use timestamps for that Commented May 8, 2018 at 13:18
  • Thanks @charlietfl. Yes, I am writing timestamps, but there is a 0.01% chance that two timestamps are written at the same exact same time. When that happens functions will have different execution times (and that would allow me to add a suffix to the last function checking the database) . That's why I am developing this function. Commented May 8, 2018 at 13:22
  • I am running an Arduino program on a IoT device with a unique MAC Address that is connecting to the database to the '/doors/' + {MAC Address} + '/ins'. There is a sensor that does that. Commented May 8, 2018 at 14:08
  • 1
    @JoaoAlvesMarrucho Could you emphasize what is not working (or should work differently) in the solution we worked out last week? Commented May 8, 2018 at 14:09
  • 1
    @JoaoAlvesMarrucho I have seen you figured out a couple of solutions, one proposed by Renaud Tarnec and another one you found (more effective). Could you post both of them as an answer, please? Just to keep the forum ordered and useful. Commented Jun 13, 2018 at 13:23

1 Answer 1

1

This question originated two different approaches. Please find them here:

1) By Renaud Tarnec using the Cloud Function

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

2) the second approach was a more direct one

I have decided to solve it on the Arduino program, because all doors have different MAC Addresses I simply added the MAC address to the end of of the timestamp and because no door will register two ins at the same time that did the trick for me.

Sign up to request clarification or add additional context in comments.

1 Comment

Perfect, thank you very much! You will be able to accept the answer in a couple of days.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.