嗨,我正在用这样的批处理写来保存文档:
batch.set(admin.firestore().collection('suuntoAppWorkoutQueue').doc(generateIDFromParts([serviceToken.userName, payload.workoutKey])), <QueueItemInterface>{
userName: serviceToken.userName,
workoutID: payload.workoutKey,
retryCount: 0,
processed: false,
}, {mergeFields: ['retryCount']});
根据文档:
将set()调用的行为更改为仅替换指定的字段路径。任何未指定的字段路径都将被忽略,并且保持不变。
上面说它只会替换。
但是,当我编写一个新文档时,例如doc ID不存在,mergeFields
只写retryCount
字段。
这是设计使然吗?
那么就不应该说:
将set()调用的行为更改为仅写入
代替:
将set()调用的行为更改为仅替换
答案 0 :(得分:1)
我可以按照您关于写入/替换的说法。我没有亲自检查行为,但是如果文档不存在,则如果写字段是“写”或“更新”,则该行为比“替换”更适合描述行为,因为一开始就没有要替换的内容。
如果仅在文档已存在的情况下仅想更新该字段,则可以使用事务来进行更新。您可以使用该事务获取文档的最新版本,检查其是否存在,如果有,请进行更新。
let data = {
userName: serviceToken.userName,
workoutID: payload.workoutKey,
retryCount: 0,
processed: false,
}
let db = admin.firestore()
let documentReference = db.collection('suuntoAppWorkoutQueue').doc(...)
db.runTransaction((transaction) =>
transaction.get(documentRef).then((doc) => {
if (doc.exists) {
return t.update(documentRef, {retryCount: data.retryCount});
} else {
return t.set(documentRef, data);
}
}
).then(...).catch(...)
事务还具有原子性的优点。如果自获取以来服务器上的值已更改,则事务将失败。在这种情况下,Firestore实际上将重新运行您的代码以重新尝试更新。这消除了比赛条件。