node.js - Google Cloud Platform/Firebase Function 未通过 onWrite 触发

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

我的应用程序使用了 Firestore Function Triggers根据 Firestore 中的更改执行后台操作,例如用户配置文件更改。例如,如果他们更改手机号码,则会发送验证码。
我有一个触发器应该在 onWrite() 时运行事件发生在特定的集合上。 onWrite()在 Firebase 中针对特定集合发生以下任何操作时运行:

  • onCreate()
  • onUpdate()
  • onDelete()

  • 在我的用例中,我需要它运行 onCreate()onUpdate() ,因此我使用 onWrite()对于 Firebase Triggers to work ,除了代表已创建/更改/删除的文档的文档 ID/通配符之外,还需要特定格式。
    常量:
    const collections = {
        ...
        conversations: "conversations",
        ...
    }
    
    可调用函数 (更新firestore):
    /**
     * Add an conversation to conversations collection
     * @type {HttpsFunction & Runnable<any>}
     */
    exports.addConversations = functions.https.onCall(async (data, context) =>  {
        // expects conversation & interested state
        const {valid, errors} = validateRequiredBody(data, [
            "conversation",
        ]);
        if (!valid) {
            return {
                status: false,
                message: "Missing or invalid parameters",
                errors: errors,
                jwtToken: "",
            };
        }
    
        // get conversation item
        const conversation = {
            id: data["conversation"]["id"],
            name: data["conversation"]["name"],
        }
    
        // create conversation with empty counter
        // let writeResult = await collectionRefs.conversationsRef.doc(conversation.id).set({
        let writeResult = await admin.firestore().collection(collections.conversations).doc(conversation.id).set({
            id: conversation.id,
            name: conversation.name,
            count: 0
        });
        console.log(`[function-addConversations] New Conversation [${conversation.name}] added`);
    
        return {
            status: true,
            message: ""
        }
    });
    
    Firestore 触发器 (不触发):
    /**
     * On conversations updated/removed, update corresponding counter
     * @type {CloudFunction<Change<QueryDocumentSnapshot>>}
     */
    exports.onConversationProfileCollectionCreate = functions.firestore.document(`${collections.conversations}/{id}`)
        .onWrite(async snapshot => {
            console.log("Conversation Collection Changed");
            // let conversation = collectionRefs.conversationsRef.doc(snapshot.id);
            // await conversation.update({count: FieldValue.increment(1)});
        });
    
    在我的移动应用程序中,用户(调用)addConversations() firebase 功能,这会将新对话添加到 Firestore,这是清晰可见的,但计数器触发器(触发功能)不运行。
    模拟器输出:
    ...
    {"verifications":{"app":"MISSING","auth":"MISSING"},"logging.googleapis.com/labels":{"firebase-log-type":"callable-request-verification"},"severity":"INFO","message":"Callable request verification passed"}
    [function-addConversations] New Conversation [Test Conversation Topic] added
    Profile updated 
    (print profile data)
    ...
    
    我应该期待看到的:
    ...
    {"verifications":{"app":"MISSING","auth":"MISSING"},"logging.googleapis.com/labels":{"firebase-log-type":"callable-request-verification"},"severity":"INFO","message":"Callable request verification passed"}
    [function-addConversations] New Conversation [Test Conversation Topic] added
    Conversation Collection Changed      // this is output by the trigger
    Profile updated 
    (print profile data)
    ...
    
    我做错什么了吗?

    最佳答案

    问题是离家较近的一个。
    我正在使用 firebase emulators 进行开发并使用 Flutter 内置于 emulator feature 中的 firebase 包中的模拟器添加连接到它们.
    Firebase 模拟器设置,例如Firebase Functions可以找到 here
    TL;博士:
    启动 Firebase 模拟器时,您应该会看到类似于以下内容的内容:

    C:\Users\User\MyApp\awesome-app-server>firebase emulators:start --only functions
    i  emulators: Starting emulators: functions
    !  functions: You are running the functions emulator in debug mode (port=9229). This means that functions will execute in sequence rather than in parallel.
    !  functions: The following emulators are not running, calls to these services from the Functions emulator will affect production: auth, firestore, database, hosting, pubsub, storage
    !  Your requested "node" version "12" doesn''t match your global version "14"
    i  ui: Emulator UI logging to ui-debug.log
    i  functions: Watching "C:\Users\User\MyApp\awesome-app-server\functions" for Cloud Functions...
    >  Debugger listening on ws://localhost:9229/03dc1d62-f2a3-418e-a343-bb0b357f7329
    >  Debugger listening on ws://localhost:9229/03dc1d62-f2a3-418e-a343-bb0b357f7329
    >  For help, see: https://nodejs.org/en/docs/inspector
    !  functions: The Cloud Firestore emulator is not running, so calls to Firestore will affect production.
    !  functions: The Realtime Database emulator is not running, so calls to Realtime Database will affect production.
    
    ...
    
    但是你会看到这个 - 这是非常重要的!
    i  functions[us-central1-api-user-onConversationProfileCollectionCreate ]: function ignored because the database emulator does not exist or is not running.
    
    这是因为 Firestore 和(实时)数据库使用在函数中找到的触发器,函数期望找到本地 Firestore/数据库模拟器。
    没有 Firestore/数据库模拟器在本地运行
    !  functions: The Cloud Firestore emulator is not running, so calls to Firestore will affect production.
    !  functions: The Realtime Database emulator is not running, so calls to Realtime Database will affect production.
    
    并且这些函数不会自动附加到生产 Firestore/数据库(这可能会造成破坏),这些触发器没有按我预期的那样运行 模拟 本地。
    解决方案:
  • 使用 firebase emulators:start --only functions,...,firestore,database 在本地模拟 Firestore 和数据库(请参阅 this 将 Firestore 数据导入本地模拟器)
  • 上传函数以使用 Firestore/数据库( 请小心执行此操作 )

  • 更多详情:
    下面我提供了导致我遇到问题的详细信息,以及我是如何解决问题的:
    我在做什么:
    firebase emulators:start --inspect-functions --only functions,auth
    
  • [本地] Firebase 函数 我正在使用 Firebase 函数为我的移动应用程序开发和测试后端以实现各种交互。
  • Firebase Auth通过使用 custom tokens 在本地处理在我的 firebase 函数应用程序中,我使用本地身份验证进行测试

  • 我已经用数据预先填充了我的 Firestore,因此我打算在本地模拟时使用 Firestore 数据,这已按预期工作,但是由于在本地模拟它们,firebase firestore 和数据库触发器将不起作用。
    我知道我的一些触发器 DID 事实上触发正确,因此它一定是某种配置错误。
    扩展解决方案 (将 firestore 数据导入本地模拟器)
    firebase 模拟器:开始 --inspect-functions --only 函数、auth、firestore、数据库
    请注意最后 2 个,firestore 和数据库 - 应该添加它以使触发器在本地工作
  • 我注意到在启动时查看日志时,指示某些功能将无法运行的文本。这让我意识到我犯了一个严重的错误——原因。

  • 从生产 Firestore 导入数据
    使用生产(开发期间)firestore 的原因是不要为每个测试重新创建所有数据。解决方案是从 firestore 导出并将您的数据导入模拟器。
    看到这个 details - 我无法从终端导出,因此我转到 Google Console 导出到存储桶,然后从那里通过控制台下载。
    要启动模拟器(并允许调试 firebase 功能),我使用:
    firebase emulators:start --inspect-functions --import ./functions/{path/to/data} --only functions,auth,firestore,database
    
    细节:
  • firebase emulators:start - 启动模拟器
  • --inspect-functions允许通过 websockets 进行调试功能 - 例如端口 9229 上的 Webstorm NodeJs 调试器
  • --import ./functions/{path/to/data} - 使用项目根目录将数据导入 Firestore 模拟器 ./
  • --only functions,auth,firestore,database指定要模拟的模块
  • 关于node.js - Google Cloud Platform/Firebase Function 未通过 onWrite 触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68220281/

    相关文章:

    mysql - 使用 Sequelize 在 nodejs 中将数组转换为批量创建

    javascript - 将 invRegex.py 移植到 Javascript (Node.js)

    java - Android Firebase OnDataChange 未触发

    javascript - firestore函数错误: Unexpected error while acquiring application default credentials

    firebase - 使用FirebaseUI将Firestore存储到recyclerview中,没有显示数据

    node.js - 客户端如何知道它是否已登录(服务器上的 passportjs 和 express)?

    android - 在 Firebase 中获取用户名、姓氏和 ID

    javascript - Firebase:返回数组中具有 id 的所有集合项,以便执行 `onSnapshot`

    node.js - 如何从 firebase 集合中获取所有文档,其中每个文档都有一些子集合并且在子集合中有一个文档?

    javascript - 这个curl 请求的node.js 等价物是什么?