'Firestore: How to insert a document with automatic id while enforcing unique field value?

In Firestore, I have a collection of fruits containing documents with automatically generated ids, and a name property.
I want to insert a new fruit document, with an automatically generated id, and only if no other with the same name exists.
Inspired by this answer, I try this:
Edit: For the record, as detailed in the accepted answer: this code is NOT transactionally safe: it does NOT prevent race conditions which could insert the same fruit name under heavy load

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

But I wonder: is newRef guaranteed to be un-used?
Otherwise, does the transaction automatically retries (due to the create failing) until success?
Otherwise, how can I insert my fruit?

Note: I use the node.js admin SDK, but I think the problem is the same with the javascript API.

Edit: here is how I do it finally:

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



Solution 1:[1]

is newRef guaranteed to be un-used?

It is virtually guaranteed to be unique. The chances of two randomly generated document IDs is astronomically small.

See also:

One thing you should be aware of is that your code is not actually transactionally safe. There is nothing stopping two clients from adding a new fruit where name=banana in a race condition between the moment of the query and the moment the transaction actually creates the new document. Under low traffic situations it's probably OK, but you are taking a chance on that.

In fact, Firestore doesn't have a built-in way to ensure uniqueness of a document's field value. It will require a fair amount of extra work to implement that yourself, perhaps by using that field value as the unique key in another collection, and making sure that collection is part of a bigger transaction that deals with the documents in your fruits collection.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Doug Stevenson