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

Flutter中从Firestore获取用户专属收藏宠物数据的实现方案及逻辑优化问询

Hey there! Let's break down your problem step by step and work out the best solution for you.

问题诊断与核心问题

首先,你的当前getFavoritePets逻辑是不正确的,导致它返回所有宠物,主要有两个原因:

  • 你没有过滤当前用户的收藏记录:只是检查了favorite: true,但任何用户的收藏标记都会触发宠物添加,完全没关联到当前登录用户
  • 异步操作顺序错误:element.reference.collection('favorites').where(...).get()是异步任务,你在它还没返回结果时就直接把宠物加入列表了,而且不管查询是否命中用户的收藏,都会执行添加操作

另外,关于集合结构的选择:两种存储方式都可行,但各有明显的效率差异:

  • 当前结构(宠物文档下的favorites子集合):适合统计单只宠物的收藏量,但要获取用户的所有收藏,需要遍历所有宠物,当宠物数量较多时,效率会非常低
  • 推荐结构(用户文档下的favorites子集合/字段):把用户收藏的宠物ID存在用户的关联集合中,获取收藏时只需先拉取用户的收藏ID列表,再批量查询对应宠物,性能和逻辑清晰度都更优

方案1:基于现有结构修复查询逻辑

如果你想保留当前的集合设计,可以修改getFavoritePets方法,确保只添加当前用户标记为收藏的宠物:

List<PetsModel> favoritePets = [];
void getFavoritePets() {
  emit(AppGetFavoritePetsLoadingState());
  favoritePets.clear(); // 清空旧数据,避免重复添加
  
  FirebaseFirestore.instance.collection('pets').get().then((petsSnapshot) {
    // 用Future.wait等待所有宠物的收藏查询完成
    Future.wait(petsSnapshot.docs.map((petDoc) {
      // 直接用当前用户ID查询该宠物下的收藏记录,比where更高效
      return petDoc.reference
          .collection('favorites')
          .doc(userModel.uId)
          .get()
          .then((favoriteDoc) {
        // 只有当用户的收藏记录存在且状态为true时,才添加宠物
        if (favoriteDoc.exists && favoriteDoc.data()['favorite'] == true) {
          favoritePets.add(PetsModel.fromJson(petDoc.data()));
        }
      });
    })).then((_) {
      // 所有查询完成后再发送成功状态,确保数据完整
      emit(AppGetFavoritePetsSuccessState());
    }).catchError((error) {
      emit(AppGetFavoritePetsErrorState(error.toString()));
    });
  }).catchError((error) {
    emit(AppGetFavoritePetsErrorState(error.toString()));
  });
}

方案2:优化集合结构(推荐)

更高效的做法是调整收藏数据的存储位置,把用户的收藏关联到用户文档下,这样能大幅提升查询效率:

第一步:修改收藏方法

void petFavorite(String petId) {
  FirebaseFirestore.instance
      .collection('users')
      .doc(userModel.uId)
      .collection('user_favorites')
      .doc(petId)
      .set({
        'favorite': true,
        'addedAt': FieldValue.serverTimestamp() // 可选:记录收藏时间,用于排序
      }).then((value) {
        emit(AppGetFavoritesSuccessState());
      }).catchError((error) {
        emit(AppGetFavoritesErrorState(error.toString()));
      });
}

第二步:实现高效的收藏宠物查询方法

List<PetsModel> favoritePets = [];
void getFavoritePets() {
  emit(AppGetFavoritePetsLoadingState());
  favoritePets.clear();
  
  // 先获取当前用户收藏的所有宠物ID
  FirebaseFirestore.instance
      .collection('users')
      .doc(userModel.uId)
      .collection('user_favorites')
      .where('favorite', isEqualTo: true)
      .get()
      .then((favoritesSnapshot) {
        if (favoritesSnapshot.docs.isEmpty) {
          emit(AppGetFavoritePetsSuccessState());
          return;
        }
        // 提取所有收藏的宠物ID
        List<String> favoritePetIds = favoritesSnapshot.docs.map((doc) => doc.id).toList();
        
        // 批量查询这些宠物的详细数据
        FirebaseFirestore.instance
            .collection('pets')
            .where(FieldPath.documentId, whereIn: favoritePetIds)
            .get()
            .then((petsSnapshot) {
              favoritePets.addAll(petsSnapshot.docs.map((doc) => PetsModel.fromJson(doc.data())).toList());
              emit(AppGetFavoritePetsSuccessState());
            }).catchError((error) {
              emit(AppGetFavoritePetsErrorState(error.toString()));
            });
      }).catchError((error) {
        emit(AppGetFavoritePetsErrorState(error.toString()));
      });
}

这种方式的优势:

  • 无需遍历所有宠物,只查询用户收藏的目标宠物,性能提升明显
  • 逻辑更贴合“用户-收藏”的关联关系,便于后续扩展(比如按收藏时间排序、取消收藏等)
  • 避免了大量冗余的异步查询,代码可读性更高

内容的提问来源于stack exchange,提问作者Mahmoud Al-Haroon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 17:39:07