Removing an object from an array in Firestore

Viewed 2879

I'm just getting into Firebase, and really digging it so far, but I'm having a bit of an issue using a Cloud Function to remove an item from an array in a collection. In the app I'm using, users have a document in a users collection that contains user-specific data that doesn't fit within the authentication model. The data looks like this:

Screenshot of user collection structure.

(It's a fitness-related app, hence the array being called 'workouts')

The user has the ability to create a workout, and when they do, after it's created, a cloud function watching for new workouts adds the ID of the newly created workout to the user document, appending it to the workouts array using arrayUnion:

exports.addWorkoutToAuthorsListOfWorkouts = functions.firestore
    .document('workouts/{workoutId}')
    .onCreate((snap, context) => {
      const id = context.params.workoutId
      const name = snap.data().title
      const uid = snap.data().author

      const workout_reference = { id: id, name: name, uid: uid }
      const workoutsRef = admin.firestore().collection("users").doc(uid)

      return workoutsRef.update({
        workouts: admin.firestore.FieldValue.arrayUnion(workout_reference)
      })
    })

This works fine, but I want the user to be able to delete workouts, and I didn't add a string to the workouts array, but instead an object like this:

{ id: "1214", name: "My workout", uid: "123asd" }

Now, for this exact use-case I could delete the array in my ReactJS app and then do an update, but I'm going to be adding the ability for users to "like" the workouts of other users, which will result in a reference to the workout being added to "workouts" in their personal user document. So if I, as a creator of a workout, delete my workout, I need to be able to delete it from the workouts array of any user who has it. Using arrayRemove didn't work because (I assume) I couldn't pass the object to be removed.

What's the best-practices way to do this? I made this attempt:

exports.removeWorkoutFromAuthorsListOfWorkouts = functions.firestore
  .document('workouts/{workoutId}')
  .onDelete((snap, context) => {

    const id =  context.params.workoutId
    const uid = snap.data().author
    const name = snap.data().name
    let newWorkouts = new Array()

    admin.firestore().collection("users").doc(uid).collection("workouts").get().then((querySnapshot) => {
      querySnapshot.forEach((doc: any) => {
          if (doc.id !== id) {
            newWorkouts.push(doc.data())
          }
      });
    });

    const workoutsRef = admin.firestore().collection("users").doc(uid)

    return workoutsRef.update({
      workouts: newWorkouts
    })
  })

But Firebase didn't like it at all, and I'm new enough to the platform that I realize this is most likely due to the result of a knowledge gap, rather than any problem with Firestore or Cloud Functions.

Any help you could provide would be very much appreciated. Cheers!

UPDATE: Got it working, with the following code:

exports.removeWorkoutFromSubscribersListOfWorkouts = functions.firestore
  .document('workouts/{workoutId}')
  .onDelete((snap, context) => {
    const workoutId =  context.params.workoutId
    const subscribers = snap.data().subscribers
    let newWorkouts = new Array()

    subscribers.forEach(subscriber => {
      let userRef = admin.firestore().collection("users").doc(subscriber)

      return userRef.get().then(doc => {
        return userRef.update({
          workouts: doc.data().workouts.filter(workout => workout.id !== workoutId)
        })
      })
    })
    .catch(() => {
      console.log("error")
    })
  })
0 Answers
Related