Firestore唯一索引还是唯一约束?

时间:2017-11-29 00:38:59

标签: google-cloud-firestore

Firestore中是否可以定义具有唯一约束的索引?如果没有,如何在文档字段上强制实现唯一性(不使用文档ID)?

3 个答案:

答案 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您只需在您的收藏夹上使用添加方法