node.js - 使用给定的 uid 首次插入 Cloud Firestore 文档时触发 Firebase Cloud 函数

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

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

以下代码在插入 newUserId 时触发

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

要求--

  • 文件:帖子
  • 字段:id、标题、uid

id 是文档 ID。

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

最佳答案

编辑后的回复(以下是评论中的澄清):

数据结构:

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

云函数代码:

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

// 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;
     });
}

<小时/> 原始回复(针对每个团队私有(private)的帖子):

假设:

  • 检查用户在特定团队而非平台范围内的第一篇帖子。
  • 未知的数据结构 - 我使用了我认为适合您现有结构的数据结构。

数据结构:

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* 函数可能会被多次调用。
  • 以上代码未考虑missing documents returned from listDocuments()getCollectionSize() 函数中。在上面的示例中,这不是问题,因为 {userId}/posts 集合没有任何子集合。不过,如果您在其他地方调用它,请务必小心。
  • 不包含错误处理
  • 使用 async/await 语法可以使其更简洁
  • 以上代码是在未部署的情况下编写的,可能存在错误/拼写错误

关于node.js - 使用给定的 uid 首次插入 Cloud Firestore 文档时触发 Firebase Cloud 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58713425/

相关文章:

javascript - 如何在 Cloud Functions for Firebase 中实现 json 对象?

node.js - 错误 : ENOENT, 打开 favicon.ico

linux - 在端口 80 上使用 pm2 启动应用程序时,应用程序生成 "Error: listen EACCES"?

javascript - 如何让 JSLint 满意 Node.js 代码中对 Uint8Array 的引用?

transactions - 具有多个 get 的 Firestore 事务

android - 如何在Flutter中打印列表后防止自动向下滚动

javascript - Nodejs path.resolve 未定义

swift - 为什么我的 SwiftUI 列表再次追加所有对象而不是更新现有对象?

javascript - 解析错误: Unexpected token selectWinner in Firebase cloud function - Node. js V10

node.js - 尝试通过云功能将文件从存储上传到 FTP 服务器时超时