klapinski
klapinski

Reputation: 161

Deleting user account triggers deletion of another nodes

Db structure:

--followers
  -followedUser1
   -user1
  -followedUser2
   -user1
   -user2
--users
  -user1
   -followed
    -followedUser1
    -followedUser2
  -user2(followedUser1)
   -followed
    -followedUser2
  -user3(followedUser2)

Everytime user follows(onCreate) & unfollows(onDelete) under followers/{followedUser}/{followerUser} path, it triggers function which increment or derement count and assigning or detaching posts from follower. It's working via fanout method, and there're no problems. Now, worse part comes when some user deletes account completely together with detaching his followers from himself(because his account will be a ghost), i've set trigger onDelete to indicate whenever it'll happen, then iterating through this user's (i.e.user3) followers removes himself from corresponding followers plus his account, it looks like this then:

--followers
  -followedUser1
   -user1
  -followedUser2
   -user1
   -user2
--users
  -user1
   -followed
    -followedUser1
  -user2(followedUser1)

Now, problematic part - when promise returns i'd like to also remove whole follower/followedUser2(because it's a ghost now) path but... there is a trigger which unfortunately executes for every follower under(onDelete). So, is there any chance to remove path above(levelup) deletetion trigger without triggering children itself? Or any other approach would be great, thanks

edit: Dont get me wrong, it'll work but if number of followers under followedUser would be "a lot" server will die after 100... trigger

Upvotes: 0

Views: 319

Answers (2)

Thomas Bouldin
Thomas Bouldin

Reputation: 3725

It looks like your multiple-update problem can be fixed with a multi-location updates

In very quickly hacked together and not tested typescript:

export const cleanupFollowers = functions.auth.user().onDelete(event => {
  const user = event.data.userId;
  const followersNode = admin.database().ref(`followers/${user}`);
  const followers = _.keys(await followersNode.once('value'));

  // Every follower also has a reverse node for this user. Get the list of keys:
  const reverseNodesToDelete = followers.map(follower => `followers/${follower}/${user}`);
  // Model this update as a map of deep key -> null to delete all at once
  let cleanup = _.keyBy(reverseNodesToDelete, null);
  // add one more update: deleting full node for the deleted user.
  cleanup[`followers/${user}`] = null;

  // do all deletions as one database request:
  return admin.database().ref().update(cleanup);
 }

Note that this will still fire your counting function, but that should be fine to run in parallel. It probably makes your app simpler to have each invariant captured separately.

Upvotes: 1

Jen Person
Jen Person

Reputation: 7546

At this time, there is no way to filter what deletion events will trigger the function, so you are correct, the function will be triggered once for each user the deleted user was following. I recognize this is one of many use cases where such functionality would be useful, so if you get a chance, please fill out a feature request here.

Upvotes: 3

Related Questions