Reputation: 869
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:
Any thoughts?
Upvotes: 0
Views: 83
Reputation: 869
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.
Upvotes: 1