在这种情况下,我使用的是循环函数,找不到解决方法。
有一个集合,其中有一个标志来告知数据是否已更改。也要记录更改。
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语句中,因为该标志已经可以被更新,并且需要进行新文档更新,因此必须写入新日志。
答案 0 :(得分:4)
如果我的理解正确,那么这里的问题是updated
标志未指定更新响应的 事件(因为您实际上不能使用{ {1}})。换句话说,您可能同时对boolean
进行了“第一阶段”写入,因此需要一种消除它们歧义的方法。
以下是我可以尝试的几种可能的选择-从(恕我直言)到最坏:
选项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
})
}
我遇到了确切的问题,必须区分服务器和客户端的更改,而忽略来自服务器的更改。希望您能尝试一下我的建议。