Flutter:从Firestore嵌套映射获取IsVegan字段并实现属性匹配
问题描述
我想将当前用户的IsVegan属性与产品的IsVegan属性做匹配,匹配成功显示绿色勾选图标,否则显示红色叉号图标。目前已通过ProductModel实例成功获取产品属性,相关代码如下:
产品卡片代码(product_card_vertical.dart)
Positioned( bottom: 0, left: 0, child: product.productPreferences!.isVegan && // 此处需填入用户的IsVegan属性 ? NCircularIcon( icon: Icons.check_circle, color: NColors.primary, height: 33, width: 30, size: 23, ) : NCircularIcon( icon: Icons.cancel, color: NColors.red, height: 33, width: 30, size: 23, ), ),
我尝试通过Firestore查询获取用户属性,编写了以下方法:
Future<UserModel> fetchUserIsVegan() async { try { final documentSnapshot = await _db .collection("Users") .doc(AuthenticationRepository.instance.authUser?.uid) .get(); userMap2 = documentSnapshot.data(); print(userMap2); if (documentSnapshot.exists) { return UserModel.fromSnapshot(documentSnapshot); } else { return UserModel.empty(); } } catch (e) { throw 'Something went wrong. Please try again'; } }
但我无法通过document.get从Firestore的嵌套映射中获取IsVegan布尔值,我的Firestore数据结构为:用户文档下包含userPreferences嵌套字段,该字段内有IsVegan属性。
解决方案
1. 修正UserModel的解析逻辑
首先检查UserModel的fromSnapshot方法,确保正确解析嵌套的userPreferences字段。示例代码如下:
class UserModel { final bool isVegan; UserModel({required this.isVegan}); factory UserModel.fromSnapshot(DocumentSnapshot snapshot) { final data = snapshot.data() as Map<String, dynamic>; // 取出嵌套的userPreferences,为空则返回空Map避免报错 final userPreferences = data['userPreferences'] as Map<String, dynamic>? ?? {}; return UserModel( // 读取IsVegan,默认值设为false防止空值 isVegan: userPreferences['IsVegan'] ?? false, ); } static UserModel empty() => UserModel(isVegan: false); }
2. 在Widget中异步获取并匹配属性
在product_card_vertical.dart对应的Widget里,用FutureBuilder异步获取用户数据,再完成属性匹配:
// 替换原有的Positioned子组件 Positioned( bottom: 0, left: 0, child: FutureBuilder<UserModel>( future: fetchUserIsVegan(), builder: (context, snapshot) { // 加载状态显示占位容器 if (snapshot.connectionState == ConnectionState.waiting) { return const SizedBox(width: 30, height: 33); } // 获取用户IsVegan属性,默认false final userIsVegan = snapshot.data?.isVegan ?? false; // 匹配产品与用户的属性 return product.productPreferences!.isVegan && userIsVegan ? NCircularIcon( icon: Icons.check_circle, color: NColors.primary, height: 33, width: 30, size: 23, ) : NCircularIcon( icon: Icons.cancel, color: NColors.red, height: 33, width: 30, size: 23, ); }, ), ),
3. 优化数据获取(可选)
如果该卡片会频繁渲染,建议用状态管理工具(如Provider、Riverpod)提前缓存用户数据,避免重复请求Firestore:
// 示例:用Riverpod缓存用户数据 final userProvider = FutureProvider<UserModel>((ref) { return ref.watch(firestoreServiceProvider).fetchUserIsVegan(); }); // 在Widget中使用缓存数据 final userAsyncValue = ref.watch(userProvider); Positioned( bottom: 0, left: 0, child: userAsyncValue.when( loading: () => const SizedBox(width: 30, height: 33), error: (_, __) => NCircularIcon( icon: Icons.cancel, color: NColors.red, height: 33, width: 30, size: 23, ), data: (user) { return product.productPreferences!.isVegan && user.isVegan ? NCircularIcon( icon: Icons.check_circle, color: NColors.primary, height: 33, width: 30, size: 23, ) : NCircularIcon( icon: Icons.cancel, color: NColors.red, height: 33, width: 30, size: 23, ); }, ), ),
内容的提问来源于stack exchange,提问作者Safwan Norasidin
相关产品推荐
相关产品推荐

