vuex-easy-firestore icon indicating copy to clipboard operation
vuex-easy-firestore copied to clipboard

[Request] Action to handle transactions

Open poornan opened this issue 7 years ago β€’ 11 comments

I have a situation, I need transaction for example find this scenario. Here I have to increment a number before insert. How can I handle this with vuex-easy-firestore. What is the best way

[db.runTransaction(t => {
        let companyRef = db.collection('companies').doc(user.company)
        return t.get(companyRef)
          .then(doc => {
            let currentBillNumber = doc.data().currentBillNumber + 1
            t.update(companyRef, {currentBillNumber: currentBillNumber})
            billDocRef = db.collection('companies/' + user.company + '/bills').doc()
            newBillState = {
              firstname: this.firstname,
              lastname: this.lastname,
              emailaddress: this.emailaddress,
              phonenumber: this.phonenumber,
              amount: this.amount,
              items: this.items,
              slug: slug,
              timestamp: new Date().getTime(),
              type: process.env.NODE_ENV,
              vehiclenumber: this.vehiclenumber,
              sequenceNumber: currentBillNumber
            }
            t.set(billDocRef, newBillState)
          })
      }).then(result => {
        console.log('incrementAndUpdateBill Transaction success!')
      }).catch(err => {
        console.log('incrementAndUpdateBill Transaction failure:', err)
      })
    }]([url](url))

poornan avatar Nov 01 '18 19:11 poornan

Can you give your Vuex-easy-firestore config?

Sent with GitHawk

mesqueeb avatar Nov 02 '18 02:11 mesqueeb

I have a basic config,

const billsDataModule = {
  firestorePath: 'companies/{companyId}/bills',
  firestoreRefType: 'collection',
  moduleName: 'billsData',
  statePropName: 'bills',
  sync: {
    orderBy: ['timestamp', 'desc'],
    where: [['type', '==', process.env.NODE_ENV]]
  },
  serverChange: {
    addedHook: function (updateStore, doc, id, store, source, change) {
      updateStore(doc)
    },
    modifiedHook: function (updateStore, doc, id, store, source, change) {
      updateStore(doc)
    },
    removedHook: function (updateStore, doc, id, store, source, change) { updateStore(doc) }
  },
  getters: {
    getBillById: (state) => (id) => {
      return state.bills[id]
    }
  }
}

and


const userDataModule = {
  firestorePath: 'users/{userId}',
  firestoreRefType: 'doc', 
  moduleName: 'userData',
  statePropName: 'user',
  serverChange: {
    defaultValues: {
      displayName: 'Alice'
    },

    addedHook: function (updateStore, doc, id, store, source, change) {
      updateStore(doc)
    },
    modifiedHook: function (updateStore, doc, id, store, source, change) {
      updateStore(doc)
    },
    removedHook: function (updateStore, doc, id, store, source, change) { updateStore(doc) }

  },
  actions: {
    incrementAndUpdateBill (context, newBillState) {
      const user = context.state.user
      console.log(user.company)
      let billDocRef
      db.runTransaction(t => {
        let companyRef = db.collection('companies').doc(user.company)
        return t.get(companyRef)
          .then(doc => {
            let currentBillNumber = doc.data().currentBillNumber + 1
            t.update(companyRef, {currentBillNumber: currentBillNumber})
            billDocRef = db.collection('companies/' + user.company + '/bills').doc()
            newBillState.sequenceNumber = currentBillNumber
            t.set(billDocRef, newBillState)
          })
      }).then(result => {
        console.log('incrementAndUpdateBill Transaction success!')
        context.rootState.newBillState = newBillState
        router.push({ name: 'view-bill', params: { bill: billDocRef.id, company: user.company, success: 'success' } })
      }).catch(err => {
        console.log('incrementAndUpdateBill Transaction failure:', err)
      })
    }
  },
  mutations: {
    SAVE_USER_TO_FIRESTORE (state, user) {
      let currentUserInfo = {}
      if (user.displayName) currentUserInfo.displayName = user.displayName
      if (user.email) currentUserInfo.email = user.email
      if (user.emailVerified) currentUserInfo.emailVerified = user.emailVerified
      if (user.phoneNumber) currentUserInfo.phoneNumber = user.phoneNumber
      if (user.photoURL) currentUserInfo.photoURL = user.photoURL
      if (user.providerData[0].providerId) currentUserInfo.providerId = user.providerData[0].providerId
      let id = user.uid
      store.dispatch('userData/set', {id, ...currentUserInfo})
    }
  }
}

poornan avatar Nov 02 '18 02:11 poornan

Ok I will write an example of what you can do. Transactions are not natively supported now but there are ways you could more easily integrate your transaction function with your Vuex Easy Firestore module. Please give me another three hours, I have some meetings from now.

Sent with GitHawk

mesqueeb avatar Nov 02 '18 02:11 mesqueeb

That's very responsive. Thank you very much. Looking forward to learn the new way to integrate transaction.

poornan avatar Nov 02 '18 02:11 poornan

Actually, once I took a look at your code, you are doing it correctly and I don't have much to improve. Some pointers:

  • the hooks in serverChange, if you don't do anything special, you don't need to include them at all. You can entirely delete serverChange.
  • you can change db.collection('companies/' + user.company + '/bills') by getters['billsData/dbRef'] (this is a handy getter from vuex-easy-firestore. you can see the source code here)
  • do you need to modify the vuex store state as well during incrementAndUpdateBill ? You can always use the PATCH_DOC mutation, see the source code here.

finally in SAVE_USER_TO_FIRESTORE if you don't mind undefined fields from being synced to the server, you could always shorten it by doing something like:

SAVE_USER_TO_FIRESTORE (state, user) {
  const {displayName, email, emailVerified, phoneNumber, photoURL} = user
  const currentUserInfo = {displayName, email, emailVerified, phoneNumber, photoURL}
  if (user.providerData[0].providerId) currentUserInfo.providerId = user.providerData[0].providerId
  const id = user.uid
  store.dispatch('userData/set', {id, ...currentUserInfo})
}

mesqueeb avatar Nov 02 '18 06:11 mesqueeb

Thank you very much for reviewing my code. I have one more clarification, if I want to just fetch a doc for one time use, which I dont want to set to store. what is the best way?

poornan avatar Nov 03 '18 02:11 poornan

That’swhat the regular fetch is for.

Or if the Firestore path needs to be different for this one time fetch, then just use firebase.firestore().doc(path).get() directly.

Sent with GitHawk

mesqueeb avatar Nov 03 '18 02:11 mesqueeb

Now I am clear. Thanks a lot

poornan avatar Nov 03 '18 02:11 poornan

For anyone working with HOOKS, there has been a small (non-breaking) change to their behaviour.

Please read about it in the latest release.

mesqueeb avatar Jan 09 '19 07:01 mesqueeb

Thank you. I'll check this

poornan avatar Jan 11 '19 12:01 poornan


After about two years of open source, I finally got accepted for Github Sponsors!

πŸ’œ github.com/sponsors/mesqueeb πŸ’œ

A little about me:

  • I love open-source
  • 6 months ago I got a son, and am trying to be an awesome father πŸ˜…
  • I'm doing freelance work here and there as my main job

If anyone was helped with vuex-easy-firestore, I'd greatly appreciate any support!

BTW, donations get's paid DOUBLE by GitHub! (they're alchemists... 🦾)

Going forward πŸ‘¨πŸΌβ€πŸ’»

  • I got great plans for the future of vuex-easy-firestore going above and beyond!! Look forward to it!!
  • On to many more years of open-sourcing! πŸŽ‰

mesqueeb avatar Nov 25 '19 05:11 mesqueeb