如何在Firestore中自动更新不同集合中的相同字段

时间:2020-10-23 08:08:53

标签: firebase google-cloud-firestore

我正在使用Cloud Firestore作为数据库,并且有users的集合,这些集合存储了有关用户的基本信息,例如ID,姓名,姓氏,电子邮件,公司ID。

我也收藏了companies,在每个公司中我收藏了tasks。 在每个任务中,我从用户集合中分配了一个用户(用户数据已复制,因此该用户的数据与集合users中的用户相同)

问题是,当我从集合users更新用户(更改名称或电子邮件...)时,因为已复制数据,而该特定用户在tasks集合中未更改数据。

在更新集合users中的用户以自动更新tasks集合中的用户时,是否可以使用firestore?

1 个答案:

答案 0 :(得分:1)

这在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 () {
    // ...
});

请注意,您需要知道哪些是“其他(“任务”)文档,其中包含用户的详细信息”:您可能需要执行查询以获取这些文档(及其DocumentReference)。 / p>

#2通过Cloud Function在后端进行更新

编写并部署Cloud Function,该data type在任何“用户”文档更新时触发,并采用该“用户”文档的值并更新包含用户详细信息的“任务”文档。

与第一种方法类似,在这种情况下,您还需要知道哪些是包含用户详细信息的“其他”(“任务”)文档。

在您的注释之后(“是否有其他选项可以引用另一个表或放置外键?” )这是一个Cloud Function,它将更新所有具有其内容的(“ task”)文档DocumentReference包含在“用户”文档的专用数组字段taskRefs中。数组成员为documentation 参考

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('....')] 
 });