这在 NoSQL 数据库中是一个相当标准的情况,我们经常对数据进行非规范化处理并需要保持这些数据同步。
基本上你有两种可能的主要方法:
#1 来自客户端的更新
当您更新“用户”文档时,同时更新包含用户详细信息的其他文档(即“任务”)。您应该使用batched write 来执行此操作:一批写入以原子方式完成,并且可以写入多个文档。
大致如下:
// Get a new write batch
var batch = db.batch();
var userRef = db.collection('users').doc('...');
batch.update(userRef, {name: '....', foo: '....'});
let userTaskRef = db.collection('companies').doc('...').collection('tasks').doc('taskId1');
batch.update(userTaskRef, {name: '....'});
userTaskRef = db.collection('companies').doc('...').collection('tasks').doc('taskId2');
batch.update(userTaskRef, {name: '....'});
// ...
// Commit the batch
batch.commit().then(function () {
// ...
});
请注意,您需要知道哪些是“包含用户详细信息的其他(“任务”)文档:您可能需要进行查询以获取这些文档(及其DocumentReferences)。
#2 通过云函数在后端更新
编写并部署一个Cloud Function,当任何“用户”文档被更新时触发,它获取该“用户”文档的值并更新包含用户详细信息的“任务”文档。
与第一种方法一样,在这种情况下,您还需要知道哪些是包含用户详细信息的“其他(“任务”)文档。
根据您的评论(“是否有任何选项可以引用另一个表或放置外键?”)这里是一个云函数,它将更新所有(“任务”)文档DocumentReference 包含在“用户”文档中的专用数组字段 taskRefs 中。数组成员是data type 参考。
exports.updateUser = functions.firestore
.document('users/{userId}')
.onUpdate((change, context) => {
const newValue = change.after.data();
const name = newValue.name;
const taskRefs = newValue.taskRefs;
const promises = taskRefs.map(ref => { ref.update({ name: name, foo: "bar" }) });
return Promise.all(promises);
});
您很可能会在前端的“用户”文档中设置taskRefs 字段的值。 JS SDK 的内容大致如下:
const db = firebase.firestore();
db.collection('users').doc('...').set({
field1: "foo",
field2: "bar",
taskRefs: [ // < = This is an Array of References
db.collection('tasks').doc('....'),
db.collection('tasks').doc('....')]
});