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
相关产品推荐
相关产品推荐

