【问题标题】:How to load data from Firestore using keys如何使用密钥从 Firestore 加载数据
【发布时间】:2019-12-26 09:25:43
【问题描述】:

我正在尝试使用 Flutter 和 Firestore 构建电子商务应用,但在构建购物车方面遇到了挑战。使用下面的代码,我已经能够使用产品 ID 获取用户希望添加到购物车的产品。我的挑战是如何使用 id 或键从 Firestore 获取产品的详细信息并将购物车产品存储在 Firestore 或 SQLite 中,以便我可以从那里查询并将它们显示在购物车页面上。

appstate.dart


class AppStateModel extends Model {

  final Map<int, int> _productsInCart = <int, int>{};

  Map<int, int> get productsInCart => Map<int, int>.from(_productsInCart);



  void addProductToCart(int productId) {
    if (!_productsInCart.containsKey(productId)) {
      _productsInCart[productId] = 1;
    } else {
      _productsInCart[productId]++;
    }

    notifyListeners();
  }


  void removeItemFromCart(int productId) {
    if (_productsInCart.containsKey(productId)) {
      if (_productsInCart[productId] == 1) {
        _productsInCart.remove(productId);
      } else {
        _productsInCart[productId]--;
      }
    }

    notifyListeners();
  }

  void clearCart() {
    _productsInCart.clear();
    notifyListeners();
  }


}

product_display.dart 具有 onPressed 功能的页面,用于获取点击添加到购物车的商品的 id

  CupertinoActionSheetAction(
    child: const Text('Add To Cart'),
      onPressed: () {
   model.addProductToCart(products[index].id);
  },
)

product.dart

class Products{
 final  String category;
 final  String description;
 final  int id;
 final int  price;
 final  String title;
 final  String url;


 const Products( {this.category,this.description,this.id, this.price, this.title, this.url,
 });


}

CartProduct.dart

class CartProducts{
 final  String category;
 final  String description;
 final  int id;
 final int  price;
 final  String title;
 final  String url;


 const CartProducts( {this.category,this.description,this.id, this.price, this.title, this.url,
 });


}

现在假设我在产品购物车中有 id 为 1、4、6、9、11 的产品,当我使用 print(model.productsInCart.keys) 在控制台中打印时,这是输出 (1、4、6 , 9, 11),现在我的挑战是如何使用这些 id 从 Firestore 集合产品中查询 id 为 1、4、6、9、11 的产品,并将它们存储在 Firebase 或 SQLite 中,以便我可以在购物车页面供用户查看他/她在购物车中的物品。

【问题讨论】:

    标签: flutter google-cloud-firestore shopping-cart


    【解决方案1】:

    我认为这就是你想要做的是

    Firestore.instance.collection("collection").document("id").get().then((querySnapshot){
        print(querySnapshot.data);
      });
    

    显然用你的集合名称替换collection,用你试图获取的id替换id。这里我使用.then 语法,但您可以像往常一样将.then 之前的所有内容传递给FutureBuilder

    编辑: 您需要添加一个辅助方法来从 Firestore 中获取所有数据。

    Future<List<Products>> getCollection() async {
      List<int> idList = [];
      // productsInCart[key] = value; where key is id and value is amount in cart
      productsInCart.forEach((key, value) {
        idList.add(key);
      });
      List<Products> productList = [];
      for (var id in idList) {
        var documents = (await Firestore.instance
                .collection('products')
                .where('id', isEqualTo: id)
                .getDocuments())
            .documents;
        if (documents.length > 0) {
          var doc = documents[0]
              .data; // if there are multiple documents with given id get first document
          var prod = Products(
              id: doc['id'],
              title: doc['title'],
              price: doc['price'],
              category: doc['category'],
              description: doc['description']);
          productList.add(prod);
        }
      }
      return productList;
    }
    

    然后使用 FutureBuilder 构建列表

    FutureBuilder<List<Products>>(
      future: getCollection(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          var list = snapshot.data;
          return ListView.builder(
              itemCount: list.length,
              itemBuilder: (context, index) => ListTile(
                    title: Text("${list[index].title}"),
                    subtitle: Text(
                        "Amount in cart : ${productsInCart[list[index].id]}"),
                  ));
        } else {
          return Text("");
        }
      },
    );
    

    我使用FutureFutureBuilder 而不是StreamStreamBuilder,因为在云Firestore 中必须使用多个ID 进行查询是一项乏味的任务,因为Firestore 没有对 的官方支持逻辑或。因此,必须从多个流源收集数据是很困难的。只要在使用应用时不更改产品详细信息,使用 FutureBuilder 与使用 StreamBuilder 的输出相同。

    编辑 2: 要使用多个流源,请使用 async 包中的 StreamGroup。这是最终代码的样子

    Stream<List<Products>> _getCollection() async* {
      List<int> idList = [];
      // productsInCart[key] = value; where key is id and value is amount in cart
      productsInCart.forEach((key, value) {
        idList.add(key);
      });
      StreamGroup<QuerySnapshot> streamGroup = StreamGroup();
      for (var id in idList) {
        var stream = Firestore.instance
            .collection('products')
            .where('id', isEqualTo: id)
            .snapshots();
        streamGroup.add(stream);
      }
      //using map to store productDetails so that same products from multiple stream events don't get added multiple times.
      Map<int, Products> productMap = {};
      await for (var val in streamGroup.stream) {
        var documents = val.documents;
        var doc = documents[0].data;
        var product = Products.fromMap(doc);
        productMap[product.id] = product;
        yield productMap.values.toList();
      }
    }
    
    StreamBuilder<List<Products>>(
      stream: _getCollection(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          var values = snapshot.data;
          return ListView.builder(
              itemCount: values.length,
              itemBuilder: (context, index) => ListTile(
                    title: Text(values[index].title),
                    subtitle: Text(
                        "Amount in cart : ${productsInCart[values[index].id]}"),
                  ));
        } else {
          print("There is no data");
          return Text("");
        }
      },
    ),
    

    为方便起见,我添加了命名构造函数

    Products.fromMap(Map map) {
      this.id = map['id'];
      this.title = map['title'];
      this.description = map['description'];
      this.price = map['price'];
      this.category = map['category'];
    }
    

    【讨论】:

    • @tomgates 我已经编辑了我的答案。请检查它是否回答了您的问题。
    • @tomgates 我很难理解你的问题是什么。我进行了第二次编辑。看看这是否解决了你的问题??如果不是,请提供正确的描述,说明您正在尝试做什么,以及您遇到困难或遇到问题的地方。
    • @Kshitij Dhakal,我认为我的整个想法都错了,我已经编辑了我的问题,拜托。
    • @ Kshitij Dhakal,第一个解决方案虽然有效,但问题再次是每当应用程序的状态发生变化(如停止或重新启动)时,购物车中的产品就会丢失,因为它们没有存储在任何地方。我现在想要实现的是在从 Firestore 成功查询相关 id 之后,现在将它们保存在 SQLite 或称为 productsInCart 的 Firestore 集合中,然后从那里查询并将它们显示在购物车页面中,这样即使应用程序停止或重新启动后,经过身份验证的用户可以看到已添加到购物车但尚未签出的内容。
    • 嘿@tomgates 我很乐意为您提供帮助,但您的最后一个请求超出了此问题的范围。没有足够的信息让我知道您如何在购物车中添加产品(因为这是大多数人使用 db 创建购物车的地方)。因此,请提出新问题,或者我们可以继续在聊天中提供更多信息。 PS。请不要将您的问题扩展到未来的预期目的之外。
    猜你喜欢
    • 1970-01-01
    • 2014-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-28
    相关资源
    最近更新 更多