I have a requirement to insert an user record with additional properties into firestore collection when beforeUserCreated blocking function is called. The user record contains an unique field which must be 16 digits numeric value generated based on epoch miliseconds and a random value. How do I ensure the record is unique across all the user records in the collection when saving into firestore and return error if duplicate value detected?
Note:
The same document id can't be exists more then one in same collection right? So by create another document with that 16 digits numeric as document id, Then batch write with record like:
const batch = defaultFirestore.batch();
const recordRef = defaultFirestore.collection("records").doc(userId);
batch.create(recordRef, record);
const uniqueDigitsRef = defaultFirestore.collection("uniqueDigits").doc(/*16 digits numeric value*/);
batch.create(uniqueDigitsRef, emptyData);
return batch.commit();
The document says what .create
do is
Create a document with the provided object values. This will fail the batch if a document exists at its location.
So if 16 digits are already exists, This batch write would fail, Then generate new one for that record and write to database again.
Edited:
Second approach is use transaction, by use transaction, run a query with .get
to search any document with same value exists, If not create record for user.
firestore.runTransaction(transaction => {
// Generate 16 digits numeric value here
let query = collection("records").where(/*unique field*/, "==", /*16 digits numeric value*/);
return transaction.get(query).then(doc => {
if (!doc.empty) {
const recordRef = defaultFirestore.collection("records").doc(userId);
transaction.create(recordRef, record);
}
});
});
If you using .get
on non-existent document, to existent, the transaction should retry, Even it's query I did expect that works same, See this answer.
So if functions trigger closely, and the first one create the same value as another one, The second one should retry.