Flutter计算Firebase两个查询结果差异的问题求助
解决Firestore中获取用户未加入联赛列表的问题
核心问题分析
- 集合求差失效:
LeagueModel实例默认采用Object的引用比较逻辑,即使两个实例数据完全一致,toSet()也会将它们判定为不同元素,导致difference方法无法正确筛选出差异项。 - 代码笔误:函数最终返回的是
result(用户已加入的联赛列表),而非计算得到的difference(未加入的联赛列表)。 - Firestore限制:确实不支持
arrayNotContains查询语法,无法直接通过数据库查询获取未加入的联赛,需先获取已加入列表再执行本地过滤。
解决方案步骤
1. 重写LeagueModel的相等性判断规则
在LeagueModel类中重写==运算符和hashCode,确保数据相同的实例会被判定为相等(推荐用Firestore文档ID作为唯一标识):
class LeagueModel { final String id; // 其他字段定义... LeagueModel({required this.id, /* 其他构造参数 */}); // fromDocumentSnapshot构造方法... @override bool operator ==(Object other) => identical(this, other) || other is LeagueModel && runtimeType == other.runtimeType && id == other.id; @override int get hashCode => id.hashCode; }
2. 修正代码返回值错误
将函数最后一行的return result;修改为return difference;,确保返回的是计算出的未加入联赛列表。
3. 优化查询逻辑(可选,提升性能)
如果联赛数据量较大,全量获取所有联赛会浪费带宽,可改为先获取已加入联赛的ID集合,再过滤所有联赛:
Future<List<LeagueModel>> getLeaguesToJoin(DocumentReference? user) async { // 获取已加入联赛的ID集合 final joinedSnapshot = await _firestore .collection("leghe") .where('members', arrayContains: user) .get(); final joinedIds = joinedSnapshot.docs.map((doc) => doc.id).toSet(); // 获取所有联赛并过滤掉已加入的 final allSnapshot = await _firestore.collection("leghe").get(); final unJoinedLeagues = allSnapshot.docs .where((doc) => !joinedIds.contains(doc.id)) .map((doc) => LeagueModel.fromDocumentSnapshot(doc: doc)) .toList(); return unJoinedLeagues; }
修正后的完整代码
import '/models/league_model.dart'; import '/models/user_model.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:collection/collection.dart'; class DBFuture { final FirebaseFirestore _firestore = FirebaseFirestore.instance; Future<List<LeagueModel>> getLeaguesToJoin(DocumentReference? user) async { // 获取用户已加入的联赛列表 QuerySnapshot joinedSnapshot = await _firestore .collection("leghe") .where('members', arrayContains: user) .get(); List<LeagueModel> joinedLeagues = joinedSnapshot.docs .map((doc) => LeagueModel.fromDocumentSnapshot(doc: doc)) .toList(); // 获取所有联赛列表 QuerySnapshot allSnapshot = await _firestore.collection("leghe").get(); List<LeagueModel> allLeagues = allSnapshot.docs .map((doc) => LeagueModel.fromDocumentSnapshot(doc: doc)) .toList(); // 计算未加入的联赛(需LeagueModel已重写==和hashCode) List<LeagueModel> difference = allLeagues.toSet().difference(joinedLeagues.toSet()).toList(); return difference; } }
内容的提问来源于stack exchange,提问作者user289143
相关产品推荐
相关产品推荐

