Firebase功能onUpdate循环问题

Inf*_*tus 14 firebase google-cloud-functions google-cloud-firestore

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

有一个我有一个标志的集合,该标志指示数据是否已更改。也要记录更改。

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
  })

}
Run Code Online (Sandbox Code Playgroud)

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

触发:

import * as landFunctions from './lands/index'
export const landWrite = functions.firestore
.document('land/{land}')
.onWrite((change, context) => {
  return landFunctions.landWrite(change, context)
})
Run Code Online (Sandbox Code Playgroud)

小智 5

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

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

  • 第一种选择实施起来不是很优雅
  • 第一个第二个选项导致您的函数被调用两次。
  • 第三个选项意味着您的函数仅被调用一次,但是您必须在旁边维护一个单独的并行文档/集合lands

选项1

updated字段中保存某种唯一标识符(例如,字符串化JSON事件的哈希-例如hash(JSON.stringify(oldDocument)),或自定义事件ID [如果有的话])。

选项2

尝试检查updateMask传入事件属性,并丢弃影响该属性的所有写事件。

选项3

将更新状态存储在其他文档路径/集合(例如,与landUpdates集合处于同一级别的lands集合)中,并将您的云功能配置为不在该路径上触发。(如果需要,您始终可以创建另一个在路径触发的Cloud Function,landUpdates并向其添加相同不同的逻辑。)

希望这可以帮助!


Gaz*_*kus 3

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

此行具有误导性:

  const updated = newDocument && newDocument.updated === oldDocument.updated
Run Code Online (Sandbox Code Playgroud)

它应该被命名为:

  const updateStatusDidNotChange = newDocument && newDocument.updated === oldDocument.updated
Run Code Online (Sandbox Code Playgroud)

我知道您希望更新后的标志由此函数而不是客户端管理。如果情况并非如此,请告诉我。

因此,更新字段仅在该函数中改变。由于您只想记录在此函数之外所做的更改,因此您只想在更新后未更改时记录。

这是我尝试从这个角度修复您的代码:

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
  })

}
Run Code Online (Sandbox Code Playgroud)

编辑

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