【问题标题】:Trigger Firebase Cloud Function on inserting to Cloud Firestore document for the first time with given uid使用给定 uid 首次插入 Cloud Firestore 文档时触发 Firebase Cloud Function
【发布时间】:2020-03-01 22:47:55
【问题描述】:

我想在第一次使用给定的 uid 插入 Cloud Firestore 文档时触发 Cloud Function

下面的代码在插入 newUserId 时触发

functions.firestore
  .document(`teamProfile/{teamId}/teamMemberList/{newUserId}`)
  .onCreate()

要求--

  • 文档:邮寄
  • 字段:id、title、uid

id 是文档 ID。

这里,如果是 uid(user) 的第一个帖子,则应触发 Cloud 函数。

【问题讨论】:

  • 听起来很酷,而且要求非常明确。你在实现的过程中遇到了什么问题?

标签: node.js google-cloud-firestore google-cloud-functions


【解决方案1】:

编辑回复(在 cmets 中澄清后):

数据结构:

users/{userId}/posts/
 ◙ post18sfge89s
   - title: My first post!
   - t: 1572967518
 ◙ post2789sdjnf
   - title: I like posting
   - t: 1572967560

posts/
 ◙ post18sfge89s
   - title: My first post!
   - uid: someUid1
   - comments/
     ◙ comment237492384
       ...
     ◙ comment234234235
       ...
 ◙ post2789sdjnf
   - title: I like posting
   - uid: someUid1

云功能代码:

使用上述结构,您将需要两个 Cloud Functions 来管理它 - 一个用于处理每个新帖子(将信息复制到作者的帖子列表),另一个用于检查它是否是作者的第一篇帖子。

// Function: New post handler
exports.newPost = functions.firestore
  .document('posts/{postId}')
  .onCreate((postDocSnap, context) => {

    // get relevant information
    const postId = postDocSnap.id; // provided automatically
    const postTitle = postDocSnap.get('title');
    const userId = postDocSnap.get('uid');
    const postedAt = postDocSnap.createTime; // provided automatically

    // add to user's post list/index
    return firestore.doc(`users/${userId}/posts/${postId}`)
      .set({
        title: postTitle,
        t: postedAt
      });
  });

// Function: New post by user handler
exports.newPostByUser = functions.firestore
  .document('users/{userId}/posts/{postId}')
  .onCreate((postDocSnap, context) => {

    // get references
    const userPostsColRef = postDocSnap.ref.parent;
    const userDocRef = userPostsCol.parent;

    // get snapshot of user data
    return userDocRef.get()
      .then((userDocSnap) => {

        // check if "First Post Event" has already taken place
        if (userDocSnap.get('madeFirstPostEvent') != true) {
          return getCollectionSize(userPostsColRef).then((length) => {
            if (length == 1) {
              return handleFirstPostByUser(userDocSnap, postDocSnap);
            } else {
              return; // could return "false" here
            }
          });
        }
      });
  });

// Pseudo-function: First post by user handler
function handleFirstPostByUser(userDocSnap, postDocSnap) {
  return new Promise(() => {
      const postId = postDocSnap.id;
      const postTitle = postDocSnap.get('title');
      const userId = userDocSnap.id;

      // do something

      // mark event handled
      return userDocSnap.ref.update({madeFirstPostEvent: true});
    });
}

// returns a promise containing the length of the given collection
// note: doesn't filter out missing (deleted) documents
function getCollectionSize(colRef) {
  return colRef.listDocuments()
     .then(docRefArray => {
       return docRefArray.length;
     });
}


原始回复(针对每个团队的私人帖子):

假设:

  • 检查用户在特定团队中的第一个帖子,而不是整个平台。
  • 未知的数据结构 - 我使用了我认为可以很好地与您现有结构配合使用的数据结构。

数据结构:

teamContent/ 集合的结构使其可以包含不同项目的子集合,例如帖子、附件、图片等。

teamProfile/{teamId}/teamMemberList/{userId}/posts/
 ◙ post18sfge89s
   - title: My first post!
   - t: 1572967518
 ◙ post2789sdjnf
   - title: I like posting
   - t: 1572967560

teamContent/{teamId}/posts/
 ◙ post18sfge89s
   - title: My first post!
   - author: someUid1
   - comments/
     ◙ comment237492384
       ...
     ◙ comment234234235
       ...
 ◙ post2789sdjnf
   - title: I like posting
   - author: someUid1

云功能代码:

使用上述结构,您将需要两个云函数来管理它 - 一个用于处理每个新帖子(将信息复制到作者的帖子列表),另一个用于检查它是否是作者在该特定帖子中的第一个帖子 团队。

// Function: New team post handler
exports.newPostInTeam = functions.firestore
  .document('teamContent/{teamId}/posts/{postId}')
  .onCreate((postDocSnap, context) => {

    // get relevant information
    const postId = postDocSnap.id; // provided automatically
    const postTitle = postDocSnap.get('title');
    const authorId = postDocSnap.get('author');
    const postedAt = postDocSnap.createTime; // provided automatically
    const teamId = context.params.teamId;

    // add to user's post list/index
    return firestore.doc(`teamProfile/${teamId}/teamMemberList/${authorId}/posts/${postId}`)
      .set({
        title: postTitle,
        t: postedAt
      });
  });

// Function: New post by team member handler
exports.newPostByTeamMember = functions.firestore
  .document('teamProfile/{teamId}/teamMemberList/{userId}/posts/{postId}')
  .onCreate((postDocSnap, context) => {

    // get references
    const userPostsColRef = postDocSnap.ref.parent;
    const userDocRef = userPostsCol.parent;

    // get snapshot of user data
    return userDocRef.get()
      .then((userDocSnap) => {

        // check if "First Post Event" has already taken place
        if (userDocSnap.get('madeFirstPostEvent') != true) {
          return getCollectionSize(userPostsColRef).then((length) => {
            if (length == 1) {
              return handleFirstPostInTeamEvent(userDocSnap, postDocSnap);
            } else {
              return; // could return "false" here
            }
          });
        }
      });
  });

// Pseudo-function: First post by team member handler
function handleFirstPostInTeamEvent(userDocSnap, postDocSnap) {
  return new Promise(() => {
      const postId = postDocSnap.id;
      const postTitle = postDocSnap.get('title');
      const userId = userDocSnap.id;

      // do something

      // mark event handled
      return userDocSnap.update({madeFirstPostEvent: true});
    });
}

// returns a promise containing the length of the given collection
// note: doesn't filter out missing (deleted) documents
function getCollectionSize(colRef) {
  return colRef.listDocuments()
     .then(docRefArray => {
       return docRefArray.length;
     });
}


注意事项:

  • 以上代码不完全是idempotent。如果同一用户的多篇博文同时上传,handleFirstPost* 函数可能会被多次调用。
  • 以上代码在getCollectionSize() 函数中没有说明missing documents returned from listDocuments()。这不是上述示例中的问题,因为{userId}/posts 集合没有任何子集合。但是,如果您在其他地方调用它,请小心。
  • 不包含错误处理
  • 使用async/await 语法可以使其更简洁
  • 以上代码是在未部署的情况下编写的,可能存在错误/错别字

【讨论】:

  • 这真是一个了不起的清晰解决方案。我考虑过的数据结构略有不同/users/{uid} - 78hdunkl787 - name: user1 - email: user1@gmail.com - uid: 78hdunkl787 /posts/{postId} - post123 - title: Some post - uid: 78hdunkl787
  • 这里的用户和帖子是独立的集合。
  • 我已经调整了上面的代码以匹配您的 cmets。 (此外,如果文档本身也使用相同的 uid 命名,则无需将 uid 存储在文档本身中。)
  • 听起来不错,是我一直在寻找的完美解决方案。谢谢@samthecodingman
猜你喜欢
  • 1970-01-01
  • 2020-10-26
  • 1970-01-01
  • 2018-05-16
  • 2021-05-15
  • 2022-08-16
  • 2018-06-25
  • 2019-08-18
  • 2020-01-02
相关资源
最近更新 更多