如何在Flutter中按嵌套Map数组的字段查询Firebase Firestore文档
错误原因
你之前的三种写法都不符合Firestore的查询规则:
where('appointments', arrayContains: translatorName):arrayContains要求完全匹配数组中的元素,你的appointments数组元素是完整的Map对象,不可能匹配到字符串类型的翻译员名称,因此无返回结果。where('appointments.translator', arrayContains: translatorName)/where('appointments.translator', isEqualTo: translatorName):Firestore不支持直接对数组内的嵌套字段做跨元素的条件匹配,点操作符仅能用于定位固定嵌套层级的Map字段,无法遍历数组元素做校验。
解决方案
方案1:新增冗余字段(官方推荐,性能最优)
这是Firestore针对这类数组嵌套查询场景的标准最佳实践,你需要在写入/更新appointments字段时,同步维护同文档下的appointmentTranslators数组字段,该字段仅存储所有预约记录中的翻译员名称,示例结构如下:
{ "patientName": "XXX", "appointments": [ {"translator": "张明", "time": "2024-05-20", "department": "内科"}, {"translator": "李丽", "time": "2024-05-22", "department": "外科"} ], // 新增冗余字段 "appointmentTranslators": ["张明", "李丽"] }
调整后查询代码如下:
static Stream<QuerySnapshot> getSpecificUserAppointments(String translatorName) { return FirebaseFirestore.instance .collection('Patients') .where('appointmentTranslators', arrayContains: translatorName) .snapshots(); }
该方案由服务端直接过滤数据,不会浪费额外的读取配额和带宽,性能最好。
方案2:客户端过滤(仅适合小数据量场景)
如果你不想修改现有数据结构,可以先拉取全量Patients集合数据,再在客户端手动做过滤:
static Stream<List<QueryDocumentSnapshot>> getSpecificUserAppointments(String translatorName) { return FirebaseFirestore.instance .collection('Patients') .snapshots() .map((snapshot) => snapshot.docs.where((doc) { final appointments = doc.get('appointments') as List<dynamic>; return appointments.any((appt) => appt['translator'] == translatorName); }).toList()); }
注意该方案会拉取集合下的所有文档,数据量大时会产生不必要的资源消耗,不建议生产环境使用。
内容的提问来源于stack exchange,提问作者Njm Jeb
相关产品推荐
相关产品推荐

