Альтернативой кодированию этих данных в do c id является использование отдельной коллекции как своего рода ручного индекса. Затем правила безопасности могут обеспечить уникальность индекса. Итак, что-то вроде этого:
/docs/${documentId} => {uniqueField: "foo", ...}
/docmap/${uniqueField} => {docId: "doc2"}
Идея здесь в том, что сначала нужно написать запись docmap, содержащую новый do c id, прежде чем им будет разрешено писать, он делает c. Поскольку docmap привязан к нашему уникальному полю, он обеспечивает уникальность.
Правила безопасности будут выглядеть примерно так:
function getPath(childPath) {
return path('/databases/'+database+'/documents/'+childPath)
}
// we can only write to our doc if the unique field exists in docmap/
// and matches our doc id
match /docs/{docid} {
let docMapPath = 'docmap/' + request.resource.data.uniqueField;
allow write: if getData(docMapPath).docId == docId;
//todo validate data schema
}
// It is only possible to add a uniqueField to the docmap
// if it doesn't already exist for another doc
// we also validate that the doc id matches our schema
match /docmap/{uniqueField} {
allow write: if resource.data.size() == 0 &&
request.resource.data.docId is string &&
request.resource.data.docId.size() < 100
}
А запись будет выглядеть примерно так:
const db = firebase.firestore();
db.doc('docmap/foo').set('doc2')
.then(() => db.doc('docs/doc2').set({uniqueField: 'foo'})
.then(doc => console.log("success"))
.catch(e => console.error(e));
Вы также можете сделать это в транзакции или даже в пакетной операции, чтобы сделать его atomi c, но, вероятно, нет необходимости усложнять процесс; правила безопасности будут обеспечивать соблюдение ограничений.