Firestore:如何在执行唯一字段值的同时插入具有自动ID的文档?

问题描述

在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);
}

解决方法

是否保证newRef不使用?

几乎可以保证是唯一的。天文学上,两个随机生成的文档ID的机会很小。

另请参阅:

您应该意识到的一件事是您的代码实际上不是事务安全的。在查询到事务实际创建新文档之间的竞争状态中,没有什么阻止两个客户添加名称为“ banana”的新水果的。在人流少的情况下,可能还可以,但是您可以借此机会。

实际上,Firestore没有内置方法来确保文档字段值的唯一性。您可能需要大量额外的工作才能实现自己,也许是通过使用该字段值作为另一个集合中的唯一键,并确保该集合是处理水果集合中文档的更大事务的一部分。 / p>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...