【问题标题】:Firestore error: No document to update (in retry method)Firestore 错误:没有要更新的文档(在重试方法中)
【发布时间】:2021-03-29 13:48:14
【问题描述】:

我有很多餐馆。我有另一个菜单集合。我正在使用云功能,并且在更新菜单时尝试更新餐厅集合中的文档。有时发生这种情况时,餐厅可能已被删除,因此我在尝试更新之前检查该文档是否存在。这是代码:

export const menuUpdated = functions.firestore.document('menus/{menuId}').onUpdate((change, context) => {
    const menuId = context.params.menuId
    const menuAfter = change.after.data()

    const promises = []
    const promise1 = updateRestaurant(menuAfter.restaurantId)
    promises.push(promise1)

    const promise2 = doSomethingElse()
    promises.push(promise2)

    return Promise.all(promises)
});

async function updateRestaurant(restaurantId: string) {
    try {
        const restaurant = await getRestaurant(restaurantId)
        if (!restaurant) {
            return true
        }

        const ref = db.collection('restaurants/').doc(restaurantId)
        const updateObject = { 'name': 'hello'}
        await ref.update(updateObject)
        return true
    } catch (error) {
        functions.logger.error(error.message)
        return false
    }
}

async function getRestaurant(restaurantId: string) {
    const ref = db.collection('restaurants').doc(restaurantId)
    const doc = await ref.get()
    if (!doc.exists) {
        return null
    }

    const restaurant = doc.data()
    restaurant.documentId = doc.id
    return restaurant
}

这通常效果很好,但有时我会看到下面这样的错误。这就是为什么我在更新之前添加了检查文档是否存在但我仍然看到此错误的原因:

Error: 5 NOT_FOUND: No document to update: projects/XXX/databases/(default)/documents/restaurants/rClGJTKgHq3wv9SDJSDp
    at Object.callErrorFromStatus (/workspace/node_modules/firebase-admin/node_modules/@grpc/grpc-js/build/src/call.js:31:26)
    at Object.onReceiveStatus (/workspace/node_modules/firebase-admin/node_modules/@grpc/grpc-js/build/src/client.js:176:52)
    at Object.onReceiveStatus (/workspace/node_modules/firebase-admin/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:336:141)
    at Object.onReceiveStatus (/workspace/node_modules/firebase-admin/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:299:181)
    at process.nextTick (/workspace/node_modules/firebase-admin/node_modules/@grpc/grpc-js/build/src/call-stream.js:145:78)
    at process._tickCallback (internal/process/next_tick.js:61:11)
Caused by: Error
    at WriteBatch.commit (/workspace/node_modules/firebase-admin/node_modules/@google-cloud/firestore/build/src/write-batch.js:413:23)
    at DocumentReference.update (/workspace/node_modules/firebase-admin/node_modules/@google-cloud/firestore/build/src/reference.js:388:14)
    at updateRestaurant (/workspace/lib/index.js:1166:19)
    at process._tickCallback (internal/process/next_tick.js:68:7)
  code: 5,
  details:
   'No document to update: projects/XXX/databases/(default)/documents/restaurants/rClGJTKgHq3wv9SDJSDp',
  metadata: Metadata { internalRepr: Map {}, options: {} },
  note:
   'Exception occurred in retry method that was not classified as transient' }

你能看出我做错了什么吗?

【问题讨论】:

  • 这获得了多少流量?餐厅是否有可能在您阅读后立即删除,然后再更新?
  • 是的,这可能是问题所在,如果是这种情况,我是否可以忽略这些错误被记录?关于“重试方法中发生未归类为瞬态的异常”的注释呢?
  • 你解决了吗?如果是,怎么做?

标签: node.js firebase google-cloud-firestore


【解决方案1】:

您可以尝试使用事务来做到这一点:

const ref = db.collection('restaurants').doc(restaurantId);
const updateObject = { 'name': 'hello' };

await db.runTransaction(async transaction => {
    const restaurantSnapshot = await transaction.get(ref);
    if (!restaurantSnapshot.exists) {
        return;
    }
    transaction.update(ref, updateObject);
});

我从来没有在事务中做过不安全的update,所以我不是 100% 会在内部处理错误。

如果仍然错误,请尝试set(updateObject, { merge: true }) 而不是update

【讨论】:

  • 谢谢!这听起来像是一个很好的解决方案,但现在我得到“错误:10 ABORTED: Aborted due to cross-transaction contention。当多个事务尝试访问相同的数据时会发生这种情况,需要 Firestore 中止至少一个以强制执行可序列化性。”
  • 好的,看起来流量不错:) 我猜你发布的代码已经大大简化了。在代码中,如果update 失败似乎没问题。真实代码是这样吗?究竟是什么问题?如果问题是您在日志中遇到的错误,您不能只是 catch 并忽略它吗?
  • 是的,你是对的,它被简化了,但它失败了也没关系,这不是什么大问题,因为这个文档已经被删除了。我主要担心错误消息“重试方法中发生未归类为瞬态的异常”发生了一些奇怪的事情,我不明白这就是为什么忽略它不安全的原因。但是你认为问题在于它已经被删除了吗?
  • 遗憾的是,我真的不知道那张纸条是什么意思。
  • 删除“菜单”文件的操作是否与删除“餐厅”的操作相同?可能执行该操作的客户端没有执行批量写入,因此有时会在将餐厅删除应用到数据库之前处理菜单事件。
猜你喜欢
  • 1970-01-01
  • 2019-06-29
  • 2018-03-22
  • 1970-01-01
  • 2022-06-27
  • 1970-01-01
  • 2018-03-22
  • 2023-04-05
相关资源
最近更新 更多