Firebase Function With Converter Wipes Document Reference on Set()

Viewed 190

I have a scheduled function that resets an integer value back to zero in my firestore. The problem that I'm running into is that, while the merge-set succeeds (for the specified properties), it somehow resets my Organization document reference to null.

So far I've tried the following

  • Not using a converter along with the Update() function (instead of Set()). While this works, it is untyped, and I have to get rid of the converter which encapsulates the moment() to Date conversion.
  • Using Set() and simply pass the entire object.
  user.reference?.withConverter(userConverter).set(user)

This is also working but it overrides the entire user object and can lead to concurrency issues in case a user also updates his object while the timed function is running.

I'm looking for a solution that allows me to use the converter class along with a merge Set().

The User interface looks like this

export interface User extends Document {
  email?: string
  name?: string
  organization?: Organization | null
  numberOfForwards?: number
  lastForwardReset?: moment.Moment
}

with its converter like so

export class UserConverter implements firestore.FirestoreDataConverter<User> {
  toFirestore(user: User): firestore.DocumentData {
    return {
      email: user.email,
      name: user.name,
      organization: user.organization ? user.organization.reference : null,
      number_of_forwards: user.numberOfForwards,
      last_forward_reset: user.lastForwardReset?.toDate()
    }
  }
  fromFirestore(snapshot: firestore.QueryDocumentSnapshot): User {
    const data = snapshot.data()!

    return {
      reference: snapshot.ref,
      email: data.email,
      name: data.name,
      organization: data.organization ? { reference: data.organization } : null,
      numberOfForwards: data.number_of_forwards,
      lastForwardReset: moment(data.last_forward_reset.toDate())
    }
  }
}
export const resetNumberOfForwards = functions.pubsub
  .schedule('every 15 minutes')
  .onRun(async () => {
const reset = (user: User) => {
  console.log(`Resetting ${user.email} from [${user.numberOfForwards}] to [0]`)
  // Claim user reference
  user.reference
    ?.withConverter(userConverter)
    .set({ numberOfForwards: 0, lastForwardReset: Moment() }, { merge: true })
}

for the partial set to work, I've included the following snippet on top of my file

firebase.firestore().settings({
  ignoreUndefinedProperties: true
})
0 Answers
Related