在Firestore中,我有一个 fruits 集合,其中包含具有自动生成的id的文档以及一个 name 属性。
我想插入一个具有自动生成的ID的新水果文档,并且前提是不存在其他具有相同 name 的文档。
受this answer的启发,我尝试这样做:
编辑:作记录,如所接受的答案中所详述:该代码在交易上不安全:确实防止了在重负载下插入相同水果名称的竞争条件
const query = firestore.collection(`/fruits`).where("name", "==", "banana").limit(1);
await firestore.runTransaction(async transaction => {
const querySnapshot = await transaction.get(query);
if (querySnapshot.length == 0) {
const newRef = firestore.collection(`/fruits`).doc();
await transaction.create(newRef, { name: "banana" });
}
});
但是我想知道: newRef 是否保证不被使用?
否则,事务是否会自动重试(由于创建失败)直到成功?
否则,我该如何插入水果?
注意:我使用的是node.js管理SDK,但我认为问题与JavaScript API相同。
编辑:这是我最后的操作:
const hash = computeHash("banana");
const uniqueIndexRef = firestore.doc(`/fruitsNameUniqueIndex/${hash}`);
try {
await firestore.runTransaction(async transaction => {
transaction.create(uniqueIndexRef, {});
const newRef = firestore.collection(`/fruits`).doc();
transaction.create(newRef, { name: "banana" });
});
} catch (error) {
console.log("fruit not inserted", error.message);
}
答案 0 :(得分:1)
是否保证newRef不使用?
几乎可以保证是唯一的。天文学上,两个随机生成的文档ID的机会很小。
另请参阅:
您应该意识到的一件事是您的代码实际上不是事务安全的。在查询到事务实际创建新文档之间的竞争状态中,没有什么阻止两个客户添加名称为“ banana”的新水果的。在人流少的情况下,可能还可以,但是您可以借此机会。
实际上,Firestore没有内置方法来确保文档字段值的唯一性。您可能需要大量额外的工作才能实现自己,也许是通过使用该字段值作为另一个集合中的唯一键,并确保该集合是处理水果集合中文档的更大事务的一部分。 / p>