Firestore:如何在强制执行唯一字段值的同时插入具有自动 ID 的文档?
Firestore: How to insert a document with automatic id while enforcing unique field value?
在 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.jsadmin SDK,但我认为问题与javascriptAPI.
相同
编辑:这是我最终的做法:
const hash = computeHash("banana"); // md5 or else
const uniqueRef = firestore.doc(`/fruitsNameUnique/${hash}`);
try {
await firestore.runTransaction(async transaction => {
transaction.create(uniqueRef, {}); // will fail if banana already exists
const newRef = firestore.collection(`/fruits`).doc();
transaction.create(newRef, { name: "banana" });
});
} catch (error) {
console.log("fruit not inserted", error.message);
}
is newRef guaranteed to be un-used?
它几乎可以保证是独一无二的。随机生成两个文档ID的几率小得像天文数字。
另请参阅:
您应该注意的一件事是您的代码实际上不是事务安全的。在查询时刻和事务实际创建新文档时刻之间的竞争条件下,没有什么可以阻止两个客户端添加名称=香蕉的新水果。在交通不畅的情况下,它可能没问题,但你正在抓住机会。
事实上,Firestore 没有 built-in 方法来确保文档字段值的唯一性。这将需要大量额外的工作来自己实现,也许通过使用该字段值作为另一个集合中的唯一键,并确保该集合是处理水果集合中文档的更大事务的一部分。
在 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.jsadmin SDK,但我认为问题与javascriptAPI.
相同编辑:这是我最终的做法:
const hash = computeHash("banana"); // md5 or else
const uniqueRef = firestore.doc(`/fruitsNameUnique/${hash}`);
try {
await firestore.runTransaction(async transaction => {
transaction.create(uniqueRef, {}); // will fail if banana already exists
const newRef = firestore.collection(`/fruits`).doc();
transaction.create(newRef, { name: "banana" });
});
} catch (error) {
console.log("fruit not inserted", error.message);
}
is newRef guaranteed to be un-used?
它几乎可以保证是独一无二的。随机生成两个文档ID的几率小得像天文数字。
另请参阅:
您应该注意的一件事是您的代码实际上不是事务安全的。在查询时刻和事务实际创建新文档时刻之间的竞争条件下,没有什么可以阻止两个客户端添加名称=香蕉的新水果。在交通不畅的情况下,它可能没问题,但你正在抓住机会。
事实上,Firestore 没有 built-in 方法来确保文档字段值的唯一性。这将需要大量额外的工作来自己实现,也许通过使用该字段值作为另一个集合中的唯一键,并确保该集合是处理水果集合中文档的更大事务的一部分。