首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Firebase函数onUpdate循环问题

Firebase函数onUpdate循环问题
EN

Stack Overflow用户
提问于 2019-05-29 16:23:24
回答 2查看 906关注 0票数 14

我有一个循环函数的这种情况,很难找到解决方案。

我有一个集合,其中我有一个标志,它告诉我数据是否发生了变化。我还想记录这些更改。

代码语言:javascript
复制
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
  })

}

问题是,当更新标志为false时,这会写入日志两次。但也不能将日志写入ELSE语句中,因为标志可能已经更新,并且进行了新的文档更新,因此必须写入新的日志。

触发器:

代码语言:javascript
复制
import * as landFunctions from './lands/index'
export const landWrite = functions.firestore
.document('land/{land}')
.onWrite((change, context) => {
  return landFunctions.landWrite(change, context)
})
EN

回答 2

Stack Overflow用户

发布于 2019-07-03 02:38:44

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

以下是我会尝试的几个可能的选择-从最差到最好:

  • 第一个选项不太适合实现
  • 第一个和第二个选项都会导致您的函数被调用两次。
  • 第三个选项意味着您的函数只被调用一次,但是您必须与lands.

一起维护一个单独的并行文档/集合

选项1

updated字段中保存某种类型的唯一标识符(例如,字符串化的JSON事件的散列-例如hash(JSON.stringify(oldDocument)),或者自定义事件ID (如果有))。

选项2

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

选项3

将您的更新状态存储在不同的文档路径/集合中(例如,与您的lands集合处于同一级别的landUpdates集合),并将云函数配置为不在该路径上触发。(如果需要,您可以随时创建在landUpdates路径上触发的第二个云函数,并向其添加相同的逻辑或不同的逻辑。)

希望这能有所帮助!

票数 5
EN

Stack Overflow用户

发布于 2019-06-29 18:17:01

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

这一行是误导性的:

代码语言:javascript
复制
  const updated = newDocument && newDocument.updated === oldDocument.updated

应该将其命名为:

代码语言:javascript
复制
  const updateStatusDidNotChange = newDocument && newDocument.updated === oldDocument.updated

我知道您希望更新标志由此函数管理,而不是由客户端管理。如果不是这样,请告诉我。

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

下面是我尝试在这种情况下修复代码的方法:

代码语言:javascript
复制
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
  })

}

编辑

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

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56356101

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档