0
votes

I have the following structure in the Firebase database, where RoomsTemplate is a subscription room. If someone signs up for the Users node, another function (onWrite) increases the value of CountUsers.

enter image description here

and the following function decreases the value of CountUsers when users unsubscribe from node Users.

exports.recountUsers = functions.database.ref('/RoomsTemplate/{id}/CountUsers').onDelete(async (snap) => {
  const counterRef = snap.ref;
  const collectionRef = counterRef.parent.child('Users');
  const messagesData = await collectionRef.once('value');
  return await counterRef.set(messagesData.numChildren());
});

The problem is that, if I want to delete the main node of the RoomsTemplate, in this case

-MBb2ZKj-pquagHBqguS

the onDelete function won't let me delete it, but it will update the CountUsers: 0 again. Try deleting the Barrio:"Barcelona" node with another function first and then verify and delete the main node.

exports.recountUsers = functions.database.ref('/RoomsTemplate/{id}/CountUsers').onDelete(async (snap) => {
  const counterRef = snap.ref;
  const collectionRef = counterRef.parent.child('Users');  
  const messagesData = await collectionRef.once('value');

  const Barrio = await counterRef.parent.child('Barrio').once('value');

   if(Barrio.numChildren() === 0){
     return await counterRef.remove();
   }else if(Barrio.numChildren() > 0){
     return await counterRef.set(messagesData.numChildren());
   }else{
     return null;
   } 

});

But I still have the same existence problem. How can I permanently delete the main node (-MBb2ZKj-pquagHBqguS), without executing the onDelete function?

1

1 Answers

0
votes

My first thought is that you've modeled yourself into a problem here, by not following the guidance to keep your data structure flat. My recommended solution based on that is to further denormalize the data, and pull the counts into a separate top-level list. In fact, I see three top-level lists here:

RoomsTemplate
  $roomid: { Barrio: "..." }
},
RoomsTemplate_users: {
  $roomid: { "uid1" true, "uid2": true }
},
RoomsTemplate_usercounts: {
  $roomid: 2
}

Alternatively, within your current data structure, you can check if the room still exists before writing the counter. For example for the first Cloud Function that would look like:

exports.recountUsers = functions.database.ref('/RoomsTemplate/{id}/CountUsers').onDelete(async (snap) => {
  const counterRef = snap.ref;
  const roomRef = counterRef.parent;
  const roomSnapshot = await roomRef.once("value");
  if (roomSnapshot.exists()) {
    const messagesData = roomSnapshot.child("Users");
    await counterRef.set(messagesData.numChildren());
  }
  return true;
});

Since Cloud Functions execute asynchronously after the original write has completed, this once('value' (like the one you have for the collectionRef already) will always get the current snapshot from the database, which is where the room has disappeared.