获取错误:“在事务中读取的每个文档也必须在Firebase中写入” [英] Getting error: `Every document read in a transaction must also be written` in Firebase

查看:295
本文介绍了获取错误:“在事务中读取的每个文档也必须在Firebase中写入”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

伙计们!

我正在开发一个类似于 https:/的应用程序/airtasker.com 用户外包任务。
任务者将竞标任务,并等待用户批准他们的出价。

i am developing an app similar to https://airtasker.com where users outsource tasks. the taskers would bid to the tasks, and wait for the user to approve their bids.

这些是涉及的集合:


  • tasks

  • 交易

  • 出价

基本上,此功能应该:

检查给定taskId是否存在事务。
如果用户开始批准出价,则会添加一笔交易。我允许多个任务者完成任务。

check if a transaction exists with the given taskId. a transaction is added if the user starts to approve bids. i allow multiple taskers to complete the task.

如果一个交易不存在,它应该是
添加一个新的,如果它到达则标记状态正在进行所需的人力(否则待定),并更新出价集合以标记接受的出价。

if a transaction doesn't exist, it should add a new one, mark the status ongoing if it reaches the required manpower (otherwise pending), and update the bids collection to mark the bid accepted.

如果存在交易,则应该
检查当前是否已批准交易集合中的列表等于人力

if a transaction exists, it should check if the current approved list from the transactions collection is equal to the manpower

如果尚未达到配额人力,则推送新任务并访问出价集合以标记接受的出价。

if it hasn't reached the quota manpower yet, push a new tasker and access the bids collection to mark the bid accepted.

如果在最后一个条件之后,批准的列表已经达到配额人力,则将任务标记为关闭,并将交易状态更改为正在进行

if after the last condition, the approved list already reached the quota manpower, mark the task close, and change the status of the transaction as ongoing

但我一直收到此错误:


未捕获(承诺)错误:还必须编写在事务中读取的每个文档。在Transaction.com发送
(transaction.js:128)eval上的
(sync_engine.js:244)

Uncaught (in promise) Error: Every document read in a transaction must also be written. at Transaction.commit (transaction.js:128) at eval (sync_engine.js:244)

这是我的代码:

const acceptOffer = async (taskerId, taskId, bidId, offer) => {
  let bulk
  try {
    const taskRef = db.collection('tasks').doc(taskId)
    const transRef = db.collection('transactions').doc(taskId)
    const bidRef = db.collection('bids').doc(bidId)
    const fees = solveFees(offer)

    bulk = await db
      .runTransaction(async t => {
        const transdoc = await t.get(transRef)
        const taskdoc = await t.get(taskRef)
        const manpower = await taskdoc.get('manpower')

        let status = 'pending'
        if (manpower === 1) {
          status = 'ongoing'
        }

        if (!transdoc.exists) {
          t.set(transRef, {
            taskId,
            status, // pending, ongoing, completed
            approved: [
              { taskerId, ...fees }
            ]
          })

          t.update(bidRef, {
            accepted: true
          })
        } else {
          const approved = await transdoc.get('approved')
          if (manpower < approved.length) {
            approved.push({ taskerId, ...fees })
            t.update(transRef, { approved })
            t.update(bidRef, { accepted: true })

            if (manpower === approved.length) {
              t.update(taskRef, { open: false })
              t.update(transRef, { status: 'ongoing' })
            }
          }
        }
      })
  } catch (e) {
    bulk = e
    console.log('nag error', e)
    throw e
  }

  if (bulk.success) {
    swal('Offer accepted!', '', 'success')
  } else {
    swal('Oh, no!',
      'This task might already be approved',
      'error'
    )
  }
}

我被困在这里因为我不知道在哪里交易失败。很感谢任何形式的帮助。

i have been stuck here since i don't understand where the transaction failed. any help is very much appreciated.

谢谢!

推荐答案

给那些拥有相同的人问题,这是我的(hackish)解决方案:

to those who are having the same problem, here is my (hackish) solution:

对于每个条件,

添加文档写入(可以是一个 set()update() delete())对应于我的每个文档读取代码:使用 get() s。

add a document write (could be a set() update() or delete()) that corresponds to each of the document reads which in my code: the use of get()s.

并返回承诺

这里是更新后的代码:

// a transaction is added if the user starts to approve offers
// this function allows multiple taskers
const acceptOffer = async (taskerId, taskId, bidId, offer) => {
  let bulk
  try {
    const taskRef = db.collection('tasks').doc(taskId)
    const transRef = db.collection('transactions').doc(taskId)
    const bidRef = db.collection('bids').doc(bidId)

    const fees = solveFees(offer)

    bulk = await db
      .runTransaction(async t => {
        const transdoc = await t.get(transRef)
        const taskdoc = await t.get(taskRef)
        const manpower = await taskdoc.get('manpower')

        // check if a transaction exists with the given taskId
        // if it doesn't, then the task doesn't have
        // any approved bidders yet
        if (!transdoc.exists) {
          // check if there is only one manpower required for the task
          // mark the status of the transaction 'ongoing' if so
          const status = manpower === 1
            ? 'ongoing' : 'pending'

          // add a transaction with the approved tasker
          t.set(transRef, {
            taskId,
            status, // pending, ongoing, completed
            approved: [
              { taskerId, ...fees }
            ]
          })

          // mark the bid 'accepted'
          t.update(bidRef, {
            accepted: true
          })

          // hackish (to prevent firestore transaction errors)
          t.update(taskRef, {})

          return Promise.resolve(true)
        } else { // if a transaction exists with the given taskId
          const approved = await transdoc.get('approved')

          // check if the current approved list from
          // the transactions collection hasn't
          // reached the manpower quota yet
          if (approved.length < manpower) {
            // push new approved bid of the tasker
            approved.push({ taskerId, ...fees })
            t.update(transRef, { approved })

            t.update(bidRef, { accepted: true }) // mark the bid 'accepted'
            t.update(taskRef, {}) // hackish

            // if, after pushing a new transaction,
            // the approved list reached the manpower quota
            if (approved.length === manpower) {
              t.update(taskRef, { open: false }) // mark the task 'close'
              t.update(transRef, { status: 'ongoing' }) // mark the transaction 'ongoing'
              t.update(bidRef, {}) // hackish
            }
            return Promise.resolve(true)
          }
          return Promise.reject(new Error('Task closed!'))
        }
      })
  } catch (e) {
    swal('Oh, no!',
      'This task might already be closed',
      'error'
    )
    throw e
  }

  if (bulk) {
    swal('Offer accepted!', '', 'success')
  }
}

这篇关于获取错误:“在事务中读取的每个文档也必须在Firebase中写入”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆