Flutter中如何获取Firestore子集合Products的全部数据?
获取Firestore子集合全部数据的解决方案
问题描述
我的Firestore集合结构如下:
Products子集合中的文档带有productName字段。目前我能通过快照获取列表名称,代码如下:
CloudShoppingListsCart.fromSnapshot(QueryDocumentSnapshot<Map<String, dynamic>> snapshot, this.products) : shoppingListId = snapshot.id, name = snapshot.data()['name'] as String;
但我不知道如何像访问snapshot.data()那样直接获取products子集合及其字段。当前调用fromSnapshot的方法是:
Stream<Iterable<CloudShoppingListsCart>> getShoppingCartListDetails({required String shoppingCartListId}){ final shoppingList = FirebaseFirestore.instance.collection(shoppingListCollectionName) .doc(shoppingCartListId).collection(shoppingListCartCollectionName).snapshots().map((event) => event.docs .map((doc) => CloudShoppingListsCart.fromSnapshot(doc, []))); return shoppingList;
我希望能获取产品名称并在ListTile中显示,示例代码如下:
return ListTile( leading: const Icon(Icons.list), trailing: const Text( "GFG", style: TextStyle(color: Colors.green, fontSize: 15),), title: Text('List item $productsName'));
目前已经能在Column中显示列表名称,需要解决获取子集合数据并展示的问题。
解决方案
Firestore无法通过父文档快照直接获取子集合数据,必须单独发起子集合查询。以下是具体实现步骤:
1. 完善数据模型
先定义产品模型,并更新购物车模型以存储产品列表:
// 产品模型 class CloudProduct { final String productId; final String productName; CloudProduct({required this.productId, required this.productName}); factory CloudProduct.fromSnapshot(QueryDocumentSnapshot<Map<String, dynamic>> snapshot) { return CloudProduct( productId: snapshot.id, productName: snapshot.data()['productName'] as String, ); } } // 购物车模型 class CloudShoppingListsCart { final String shoppingListId; final String name; final List<CloudProduct> products; CloudShoppingListsCart({ required this.shoppingListId, required this.name, required this.products, }); factory CloudShoppingListsCart.fromSnapshot( QueryDocumentSnapshot<Map<String, dynamic>> snapshot, List<CloudProduct> products, ) { return CloudShoppingListsCart( shoppingListId: snapshot.id, name: snapshot.data()['name'] as String, products: products, ); } }
2. 修改数据流获取逻辑
在获取购物车列表的同时,异步查询每个购物车对应的products子集合:
Stream<Iterable<CloudShoppingListsCart>> getShoppingCartListDetails({required String shoppingCartListId}) { return FirebaseFirestore.instance .collection(shoppingListCollectionName) .doc(shoppingCartListId) .collection(shoppingListCartCollectionName) .snapshots() .asyncMap((event) async { // 遍历每个购物车文档,并行查询子集合数据 final futures = event.docs.map((doc) async { final productsSnapshot = await FirebaseFirestore.instance .collection(shoppingListCollectionName) .doc(shoppingCartListId) .collection(shoppingListCartCollectionName) .doc(doc.id) .collection('products') // 替换为你的products子集合实际名称 .get(); final products = productsSnapshot.docs.map(CloudProduct.fromSnapshot).toList(); return CloudShoppingListsCart.fromSnapshot(doc, products); }); return await Future.wait(futures); }); }
3. 在UI中展示产品名称
使用StreamBuilder监听数据流,遍历购物车及对应的产品列表进行展示:
StreamBuilder<Iterable<CloudShoppingListsCart>>( stream: getShoppingCartListDetails(shoppingCartListId: '你的目标列表ID'), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Text('暂无数据'); } final shoppingCarts = snapshot.data!; return Column( children: [ // 先展示购物车列表名称 ...shoppingCarts.map((cart) => Padding( padding: const EdgeInsets.all(8.0), child: Text(cart.name, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), )), // 再展示每个购物车下的产品 ...shoppingCarts.expand((cart) => cart.products.map((product) { return ListTile( leading: const Icon(Icons.list), trailing: const Text( "GFG", style: TextStyle(color: Colors.green, fontSize: 15), ), title: Text('List item ${product.productName}'), ); })), ], ); }, )
注意事项
- 确保子集合名称与Firestore控制台中的完全一致
- 若数据量较大,可考虑分页加载或使用
limit()优化性能 - 可添加
try-catch块处理查询过程中的异常情况
内容的提问来源于stack exchange,提问作者jorge
相关产品推荐
相关产品推荐

