Firestore中是否可以定义具有唯一约束的索引?如果没有,如何在文档字段上强制实现唯一性(不使用文档ID)?
答案 0 :(得分:13)
是的,可以结合使用两个集合(Firestore规则)和批处理写入来实现。
https://cloud.google.com/firestore/docs/manage-data/transactions#batched-writes
简单的想法是,使用批处理写入,将文档写入“数据”集合,并同时写入单独的“索引”集合,在该索引中索引要唯一的字段的值。
使用Firestore规则,然后可以确保“数据”集合仅在索引集合中还存在文档字段的值的情况下才可以写入文档,反之亦然,只能写入索引集合索引中的值是否与数据集合中的值匹配。
示例
假设我们有一个User
集合,并且我们想确保username
字段是唯一的。
我们的User
集合将仅包含username
/User/{id}
{
username: String
}
我们的Index
集合将在路径中包含用户名,并在value
属性中包含被索引用户的ID。
/Index/User/username/{username}
{
value: User.id
}
要创建User
,我们使用批量写入操作同时创建User
文档和Index
文档。
const firebaseApp = ...construct your firebase app
const createUser = async (username) => {
const database = firebaseApp.firestore()
const batch = database.batch()
const Collection = database.collection('User')
const ref = Collection.doc()
batch.set(ref, {
username
})
const Index = database.collection('Index')
const indexRef = Index.doc(`User/username/${username}`)
batch.set(indexRef, {
value: ref.id
})
await batch.commit()
}
要更新User
的用户名,我们使用批量写入来更新User
文档,删除先前的Index
文档并创建一个新的Index
文档同一时间。
const firebaseApp = ...construct your firebase app
const updateUser = async (id, username) => {
const database = firebaseApp.firestore()
const batch = database.batch()
const Collection = database.collection('User')
const ref = Collection.doc(id)
const refDoc = await ref.get()
const prevData = refDoc.data()
batch.update(ref, {
username
})
const Index = database.collection('Index')
const prevIndexRef = Index.doc(`User/username/${prevData.username}`)
const indexRef = Index.doc(`User/username/${username}`)
batch.delete(prevIndexRef)
batch.set(indexRef, {
value: ref.id
})
await batch.commit()
}
要删除User
,我们使用批量写入操作同时删除User
文档和Index
文档。
const firebaseApp = ...construct your firebase app
const deleteUser = async (id) => {
const database = firebaseApp.firestore()
const batch = database.batch()
const Collection = database.collection('User')
const ref = Collection.doc(id)
const refDoc = await ref.get()
const prevData = refDoc.data()
batch.delete(ref)
const Index = database.collection('Index')
const indexRef = Index.doc(`User/username/${prevData.username}`)
batch.delete(indexRef)
await batch.commit()
}
然后,我们设置Firestore规则,以便仅在用户名尚未为其他User
编制索引的情况下,才允许创建User
。仅当User
的用户名不存在时才可以更新Index
的用户名,并且也必须在删除User
的情况下也可以删除Index
。如果已经存在具有相同User
的{{1}},则创建和更新将失败,并显示“缺少权限或权限不足”错误。
username
答案 1 :(得分:0)
[这不是一个完美的解决方案,但是可以工作]
我已经使用密钥完成了这个唯一的密钥... 我希望我的表具有唯一的日期值。所以我把它作为文档的关键。 我可以通过任何方式获取所有文件
db.collection('sensors').doc(sensorId).collection("data").doc(date).set(dataObj).then(() => {
response.send(dataObj);
});
答案 2 :(得分:-1)
根据https://cloud.google.com/firestore/docs/manage-data/add-data#set_a_document部分的文档
将文档对象添加到集合中时,您可以简单地添加自定义标识符,如下所示:
const data = {
name: 'Los Angeles',
state: 'CA',
country: 'USA'
};
// Add a new document in collection "cities" with ID 'LA'
const res = await db.collection('cities').doc('LA').set(data);
在您使用 set 作为集合中的方法时,将此https://cloud.google.com/firestore/docs/manage-data/add-data#node.js_4用作参考,当您需要自动生成ID时,便可以为此类文档指定ID您只需在您的收藏夹上使用添加方法