【问题标题】:How to filter items in flutter when getting data from firebase从firebase获取数据时如何过滤flutter中的项目
【发布时间】:2021-02-19 09:00:57
【问题描述】:

我目前正在使用 FirebaseFirestore.instance.collection('cars').get() 从 Firebase 获取与汽车详细信息相关的数据。 我将所有 Car 实例保存在 List<Cars> _cars = []; 使用我在didChangeDependencies{}中执行的addCarsToList方法

Future<void> addCarsToList({BuildContext context, FilterBy filter}) async {
    var lastDocTracker =
        Provider.of<LastDocumentTracker>(context, listen: false);

    try {
      var dcs = filter != null
          ? await carsCollection.orderBy('dueDate').limit(5).where('readyToRepair', isEqualTo: false).get()
          : await carsCollection.orderBy('dueDate').limit(5).get();

//print(dcs.docs.last.data());

      for (int i = 0; i < dcs.docs.length; i++) {
        Cars carValue = singleCar(dcs, i);

        if (_cars.every((item) => item.carId != carValue.carId)) {
          _cars.add(carValue);
          notifyListeners();
        }
      }
      lastDocTracker.changeLastDocument(dcs.docs.last);
    } catch (e) {
      print(e);
    }
  }

这里我使用 lastDocumentTracer 来跟踪最后一个文档来实现分页。 因此,为了实现分页,我使用滚动控制器并调用getMore 方法

  Future<void> getMore(
      BuildContext context, QueryDocumentSnapshot lastSnap) async {
    print('getMore called');
    var lastDocTracker =
        Provider.of<LastDocumentTracker>(context, listen: false);
    var dcs = await carsCollection
        .orderBy('dueDate')
        .startAfterDocument(lastSnap)
        .limit(5)
        .get();

    if (dcs.docs.isNotEmpty)
      for (int i = 0; i < dcs.docs.length; i++) {
        Cars carValue = singleCar(dcs, i);

        if (_cars.every((item) => item.carId != carValue.carId)) {
          _cars.add(carValue);
          notifyListeners();
        }
      }
    if (dcs.docs.isNotEmpty) lastDocTracker.changeLastDocument(dcs.docs.last);
    return;
  }

我目前面临的问题是我有三个过滤器(All、Upcoming、Ready)。

全部表示来自 firebase 的所有汽车,没有任何过滤器。

即将上市表示未来即将上市的汽车。 (在 Firestore 中保存为 DateTime.millisecondsSinceEpoch)

Ready 表示准备修理的汽车(在 firestore 中保存为 bool) Have a look into the screenshot

我正在尝试使用 where((element) =&gt; isReadyToRepair) 通过汽车列表进行过滤并使用 setState 但不幸的是,我将其限制为 Firebase 中的 5 个项目,如果没有带有字段 isReadyToRepair = true 的汽车,那么我无法向下滚动并使用滚动控制器调用 getMore,因此它显示为空且未加载任何数据。

我需要你们的帮助。请帮我。如果我没有解释清楚,请告诉我。

【问题讨论】:

    标签: firebase flutter dart google-cloud-firestore


    【解决方案1】:

    如果你想同时获得 5 个,你需要对数据库进行 3 个不同的查询并使用 where 方法,你有文档 here

    您的查询看起来更像这样:

    var dcs = await carsCollection
        .orderBy('dueDate')
        .where('ready', isEqualTo: true)
        .startAfterDocument(lastSnap)
        .limit(5)
        .get();
    

    -- 更新

    这超出了主题,抱歉。您需要在 LastDocumentTracker 中创建两个不同的引用。我想您将上次跟踪的文档存储在一个变量中,所以我要做的是为过滤后的文档创建一个(或为您应用的每个过滤器创建一个),并为所有文档创建一个。然后,当您获取文档时,您会根据您应用的过滤器找到正确的变量。为了提高代码的维护性和优雅性,我会使用 addCarsToList 来获得更多和第一次获得它们:

    //New addCarsToList
    Future<void> addCarsToList(LastDocumentTracker tracker, {FilterBy filter}) async { //Tracker as required and filter as optional
        
        bool hasFilter = filter != null;
    
        var lastSnap = tracker.getLastSnap(filtered: hasFilter);
    
        bool isFirst = lastSnap != null;
    
        var dcs;
            
        try {
          if(hasFilter){
                dcs = isFirst ? await carsCollection.orderBy('dueDate').limit(5).where('readyToRepair', isEqualTo: false).get() : await carsCollection.orderBy('dueDate').startAfterDocument(lastSnap).limit(5).where('readyToRepair', isEqualTo: false).get()
          } else{
    
            dcs = isFirst ? await carsCollection.orderBy('dueDate').limit(5).get(); : await carsCollection.orderBy('dueDate').startAfterDocument(lastSnap).limit(5).get();
          }
    
          for (var doc in dcs.docs) {
            Cars carValue = singleCar(doc); // Make it get a single document, what's the point on passing both a list and an index ?
    
            if (_cars.every((item) => item.carId != carValue.carId)) { //questionable
              _cars.add(carValue);
              notifyListeners();
            }
          }
    
          lastDocTracker.changeLastDocument(dcs.docs.last, filtered: hasFilter);
        } catch (e) {
          print(e);
        }
      }
    

    我修改了很多东西,请仔细阅读所有这些内容,如果您有不明白的地方请告诉我。在此之后您应该进行很多调整,例如:

    • 在跟踪器中为过滤的项目添加一个变量;
    • 在changeLastDocument中添加“filtered”参数并修改右侧 基于此参数的变量;
    • 将跟踪器而不是上下文传递给方法(当你传递一个对象时,你传递的是它的引用,而不是一个副本,所以如果你修改它,你将修改你传递的那个;)
    • 修改 singleCar 方法以接受对象而不是列表和索引

    【讨论】:

    • 这就是我正在做的,但问题是我只在用户使用该过滤器时才需要它。
    • 对不起,我没有读完你的问题
    • @badmasW 我更新了我的答案,希望你会发现它有用。如果你没有得到什么,请告诉我:)
    • 非常感谢。我会尝试告诉你更新。
    • 谢谢,感谢@Gabriel。我终于修好了。
    猜你喜欢
    • 2019-02-07
    • 2021-04-08
    • 2020-12-01
    • 2020-09-14
    • 2021-03-04
    • 2021-11-11
    • 2012-01-21
    • 2020-08-31
    • 2021-12-04
    相关资源
    最近更新 更多