我有一个循环函数的这种情况,很难找到解决方案。
我有一个集合,其中我有一个标志,它告诉我数据是否发生了变化。我还想记录这些更改。
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语句中,因为标志可能已经更新,并且进行了新的文档更新,因此必须写入新的日志。
触发器:
import * as landFunctions from './lands/index'
export const landWrite = functions.firestore
.document('land/{land}')
.onWrite((change, context) => {
return landFunctions.landWrite(change, context)
})发布于 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路径上触发的第二个云函数,并向其添加相同的逻辑或不同的逻辑。)
希望这能有所帮助!
发布于 2019-06-29 18:17:01
这里的主要问题是无法区分此服务器功能或客户端所做的更改。每当你处于这种情况下,你都应该试着明确区分它们。您甚至可以考虑在服务器的更新中添加一个额外的字段,比如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
})
}编辑
我遇到了确切的问题,我必须区分服务器和客户端的更改,并忽略来自服务器的更改。我希望你试一试我的建议。
https://stackoverflow.com/questions/56356101
复制相似问题