简体   繁体   中英

How to return promise in case of multiple transactions?

I am trying to learn to work with firestore transactions.

Here is my code:

const handleSubmit = (e) => {
    e.preventDefault();
    console.log(message);

    let mergedId = loggedUserId + toBeContactedUserId;

    let loggedUserRef = db.collection('users').doc(loggedUserId);
    let toBeContactedUserRef = db.collection('users').doc(toBeContactedUserId);
    let messageDbRef = db.collection('messages').doc();

    db.runTransaction((transaction) => {

      transaction.get(loggedUserRef)                        //First transaction
        .then(userDoc => {
          let userData = {
            ...userDoc.data(),
            contacts: {
              ...userDoc.data().contacts,
              [toBeContactedUserId]: {
                ...userDoc.data().contacts[toBeContactedUserId],
                lastMsg: message,
                unreadMsg: 0
              }
            }
          }
          loggedUserRef.set(userData);
        })

      transaction.get(toBeContactedUserRef)                    //Second transaction
        .then(userDoc => {
          let unreadMsgInc = userDoc.data().contacts[loggedUserId].unreadMsg + 1;
          let userData = {
            ...userDoc.data(),
            contacts: {
              ...userDoc.data().contacts,
              [loggedUserId]: {
                ...userDoc.data().contacts[loggedUserId],
                lastMsg: message,
                unreadMsg: unreadMsgInc
              }
            }
          }
          toBeContactedUserRef.set(userData);
        })

      transaction.get(messageDbRef)                           ////Third transaction
        .then(msgDoc => {
          messageDbRef.set({
            from: loggedUserId,
            to: toBeContactedUserId,
            content: message,
            reaction: false,
            seen: false,
            searchId: mergedId,
            time: firebase.firestore.FieldValue.serverTimestamp()
          })
        }
        )
    })
    .then(res=>{
      console.log(res);
    })
    .catch(err=>{
      console.log(err);
    })
  }

handleSubmit() is the function which is invoked upon clicking a button. In the first transaction.get() I am doing a write operation. In the second transaction.get() I am doing a read and a write operation and in the third, I am doing a write operation.

When I am running the code I get error as: Error: Transaction callback must return a Promise

I am not clear if I am using transactions the right way. Is there a way I can write all this logic in a single transaction.get()

Please guide me on how to resolve this error.

You can use Promise.all to wrap all three promises:

db.runTransaction((transaction) => {
  const p1 = transaction.get(loggedUserRef)
    .then(userDoc => {
      ...
    })

  const p2 = transaction.get(toBeContactedUserRef)
    .then(userDoc => {
      ...
    })

  const p3 = transaction.get(messageDbRef)
    .then(msgDoc => {
      ...
    })
  return Promise.all([p1, p2, p3]); // 👈
})
.then(res=>{
  console.log(res);
})
.catch(err=>{
  console.log(err);
})

Alternatively, you can use async / await to have the compiler generate that for you and get rid of some of the nesting:

db.runTransaction((transaction) => async { // 👈
  let userDoc = await transaction.get(loggedUserRef);
  ...

  userDoc = await transaction.get(toBeContactedUserRef);
  ...

  const msgDoc = await transaction.get(messageDbRef)
  ...
})
.then(res=>{
  console.log(res);
})
.catch(err=>{
  console.log(err);
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM