Firebase功能onUpdate循环问题

时间:2019-05-29 08:23:24

标签: firebase google-cloud-firestore google-cloud-functions

在这种情况下,我使用的是循环函数,找不到解决方法。

有一个集合,其中有一个标志来告知数据是否已更改。也要记录更改。

export async function landWrite(change, context) {

  const newDocument = change.after.exists ? change.after.data() : null
  const oldDocument = change.before.data()

  const log = {
    time: FieldValue.serverTimestamp(),
    oldDocument: oldDocument,
    newDocument: newDocument
  }

  const landid = change.after.id
  const batch = db.batch()

  const updated = newDocument && newDocument.updated === oldDocument.updated

  if (!updated) {
    const landRef = db.collection('land').doc(landid)
    batch.update(landRef, {'updated': true })
  }
  const logRef = db.collection('land').doc(landid).collection('logs').doc()
  batch.set(logRef, log)

  return batch.commit()
  .then(success => {
    return true
  })
  .catch(error => {
    return error
  })

}

问题在于,当UPDATED标志为false时,它将两次写入日志。 但是也不能将日志写入ELSE语句中,因为该标志已经可以被更新,并且需要进行新文档更新,因此必须写入新日志。

2 个答案:

答案 0 :(得分:4)

如果我的理解正确,那么这里的问题是updated标志未指定更新响应的 事件(因为您实际上不能使用{ {1}})。换句话说,您可能同时对boolean进行了“第一阶段”写入,因此需要一种消除它们歧义的方法。

以下是我可以尝试的几种可能的选择-从(恕我直言)到最坏:

  • 第一个选项的实现不是很优雅
  • 第一个第二个选项两者导致您的函数 叫了两次。
  • 第三个选项表示您的功能仅 被调用一次,但是您必须维护一个单独的并行 {/ {1}}旁边的文档/集合。

选项1

lands字段中保存某种唯一标识符(例如,字符串化JSON事件的哈希-例如lands,或自定义事件ID(如果有))。

选项2

尝试检查updateMask property of the incoming event,并丢弃任何仅影响该属性的写入事件。

选项3

将更新状态存储在其他文档路径/集合中(例如与updated集合处于同一级别的hash(JSON.stringify(oldDocument))集合),并将您的Cloud Function配置为不在该路径上触发。 (如果需要,您始终可以创建 second 云函数,该函数在landUpdates路径上执行触发,并添加相同的逻辑或< / em>与之不同的逻辑。)

希望这会有所帮助!

答案 1 :(得分:2)

此处的主要问题是无法区分此服务器功能或客户端所做的更改。每当遇到这种情况时,都应尝试明确区分它们。您甚至可以考虑使用诸如fromServer: true之类的额外字段,该字段随服务器的更新一起使用,并帮助服务器忽略相关的触发器。话虽如此,我想我已经确定了问题并在下面提供了明确的解决方案。

此行具有误导性:

  const updated = newDocument && newDocument.updated === oldDocument.updated

应命名为:

  const updateStatusDidNotChange = newDocument && newDocument.updated === oldDocument.updated

我了解您希望此功能而不是客户端管理更新的标志。让我知道是否不是这种情况。

因此,仅在此功能中更改更新字段。由于您只想记录在此功能之外所做的更改,因此只想在更新未更改时记录日志。

以下是我尝试修改您的代码的方法:

export async function landWrite(change, context) {

  const newDocument = change.after.exists ? change.after.data() : null
  const oldDocument = change.before.data()

  const updateStatusDidNotChange = newDocument && newDocument.updated === oldDocument.updated

  if (!updateStatusDidNotChange) return true; //this was a change made by me, ignore

  const batch = db.batch()

  if (!oldDocument.updated) {
    const landid = change.after.id
    const landRef = db.collection('land').doc(landid)
    batch.update(landRef, {'updated': true })
  }

  const log = {
    time: FieldValue.serverTimestamp(),
    oldDocument: oldDocument,
    newDocument: newDocument
  }

  const logRef = db.collection('land').doc(landid).collection('logs').doc()
  batch.set(logRef, log)

  return batch.commit()
  .then(success => {
    return true
  })
  .catch(error => {
    return error
  })

}

编辑

我遇到了确切的问题,必须区分服务器和客户端的更改,而忽略来自服务器的更改。希望您能尝试一下我的建议。