You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase Cloud Function触发报错:'Event'对象无'after'属性

问题:Firebase Cloud Function触发时出现AttributeError

我部署了如下Python版Firebase Cloud Function,该函数需在Appointments集合中文档发生变更时触发,并向关联用户发送FCM通知。

# The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
from firebase_functions import firestore_fn, https_fn

# The Firebase Admin SDK to access Cloud Firestore.
from firebase_admin import initialize_app, firestore, messaging
import google.cloud.firestore


app = initialize_app()

db = firestore.client

@firestore_fn.on_document_updated(document="Appointments/{appointmentId}")
def send_appointment_notification(event: firestore_fn.Event[firestore_fn.DocumentSnapshot | None]):
    # Get the updated data after the update operation
    updated_data = event.after.data()

    # Access the status field from the updated data
    status = updated_data.get("status")

    if status in ['Approved', 'Declined']:
        # Get the clientId from the appointment document
        client_id = updated_data.get("clientId")

        # Retrieve user document to get the fcmtoken
        user_ref = db.collection('Users').document(client_id)
        user_doc = user_ref.get()

        if user_doc.exists:
            user_data = user_doc.to_dict()
            if 'fcmToken' in user_data:
                fcmtoken = user_data['fcmToken']

                # Compose notification message
                if status == 'Approved':
                    notification_title = f'Appointment Approved'
                elif status == 'Declined':
                    notification_title = f'Appointment Declined'

                message = messaging.Message(
                    data={
                        'appointmentId': updated_data.get("appointmentId")
                    },
                    notification={
                        'title': notification_title,
                        'body': f'Appointment on {updated_data.get("startDateTime")} has been {status.lower()}'
                    },
                    token=fcmtoken
                )

                # Send the notification
                response = messaging.send(message)
                print('Notification sent successfully:', response)
            else:
                print('No fcmtoken found for the user.')
        else:
            print(f'User document with ID {client_id} does not exist.')

    else:
        print(f'Status {status} is not Approved or Declined.')

但函数触发时,日志中出现如下错误:

Traceback (most recent call last):
  File "/layers/google.python.pip/pip/lib/python3.12/site-packages/flask/app.py", line 1473, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/layers/google.python.pip/pip/lib/python3.12/site-packages/flask/app.py", line 882, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/layers/google.python.pip/pip/lib/python3.12/site-packages/flask/app.py", line 880, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/layers/google.python.pip/pip/lib/python3.12/site-packages/flask/app.py", line 865, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/layers/google.python.pip/pip/lib/python3.12/site-packages/functions_framework/execution_id.py", line 106, in wrapper
    return view_function(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/layers/google.python.pip/pip/lib/python3.12/site-packages/functions_framework/__init__.py", line 188, in view_func
    function(event)
  File "/layers/google.python.pip/pip/lib/python3.12/site-packages/firebase_functions/firestore_fn.py", line 255, in on_document_updated_wrapped
    return _firestore_endpoint_handler(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/layers/google.python.pip/pip/lib/python3.12/site-packages/firebase_functions/firestore_fn.py", line 176, in _firestore_endpoint_handler
    func(database_event)
  File "/workspace/main.py", line 35, in send_appointment_notification
    updated_data = event.after.data()
                   ^^^^^^^^^^^
AttributeError: 'Event' object has no attribute 'after'

此前尝试使用event.data.get("status")获取状态时,还出现错误:AttributeError: 'Change' object has no attribute 'get',请帮忙解决该问题。


解决方案

你的代码存在两个关键错误,修正后即可正常运行:

1. Firestore客户端初始化错误

db = firestore.client 缺少调用括号,firestore.client是方法,需要执行它获取客户端实例:

db = firestore.client()

2. Event对象结构理解错误

在Firebase Functions v2的Python SDK中,on_document_updated触发的Event对象,变更数据存储在event.data属性中,这是一个Change对象,包含before(更新前文档快照)和after(更新后文档快照)两个属性。直接访问event.after是错误的,正确获取更新后数据的方式是:

updated_data = event.data.after.data()

同时,函数的类型注解需要修正,Event的泛型参数应为Change[DocumentSnapshot]:

def send_appointment_notification(event: firestore_fn.Event[firestore_fn.Change[firestore_fn.DocumentSnapshot]]):

修正后的完整代码

# The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
from firebase_functions import firestore_fn, https_fn

# The Firebase Admin SDK to access Cloud Firestore.
from firebase_admin import initialize_app, firestore, messaging
import google.cloud.firestore


app = initialize_app()

# 修正:调用client方法获取Firestore客户端
db = firestore.client()

@firestore_fn.on_document_updated(document="Appointments/{appointmentId}")
# 修正:正确的类型注解
def send_appointment_notification(event: firestore_fn.Event[firestore_fn.Change[firestore_fn.DocumentSnapshot]]):
    # 修正:通过event.data.after获取更新后的文档快照
    updated_data = event.data.after.data()

    # Access the status field from the updated data
    status = updated_data.get("status")

    if status in ['Approved', 'Declined']:
        # Get the clientId from the appointment document
        client_id = updated_data.get("clientId")

        # Retrieve user document to get the fcmtoken
        user_ref = db.collection('Users').document(client_id)
        user_doc = user_ref.get()

        if user_doc.exists:
            user_data = user_doc.to_dict()
            if 'fcmToken' in user_data:
                fcmtoken = user_data['fcmToken']

                # Compose notification message
                if status == 'Approved':
                    notification_title = f'Appointment Approved'
                elif status == 'Declined':
                    notification_title = f'Appointment Declined'

                message = messaging.Message(
                    data={
                        'appointmentId': event.data.after.id  # 更可靠的方式获取文档ID
                    },
                    notification={
                        'title': notification_title,
                        'body': f'Appointment on {updated_data.get("startDateTime")} has been {status.lower()}'
                    },
                    token=fcmtoken
                )

                # Send the notification
                response = messaging.send(message)
                print('Notification sent successfully:', response)
            else:
                print('No fcmtoken found for the user.')
        else:
            print(f'User document with ID {client_id} does not exist.')

    else:
        print(f'Status {status} is not Approved or Declined.')

额外优化:获取appointmentId时,使用event.data.after.id比从文档数据读取更可靠,因为文档ID是Firestore原生属性,无需依赖文档内字段。

内容的提问来源于stack exchange,提问作者Tareq Ewaida

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 22:40:57