【问题标题】:Sort Firebase Data from AsyncSnapshot<QuerySnapshot<Object?>> with Dart .sort() Function使用 Dart .sort() 函数对 AsyncSnapshot<QuerySnapshot<Object?>> 中的 Firebase 数据进行排序
【发布时间】:2021-12-19 22:32:42
【问题描述】:

我在 Firebase 查询后无法对数据进行排序。在我的数据库中,有一个bikes 的集合,每辆自行车都有一个条件:ExcellentGreatGoodFairPoorTotaled。我想按条件排序,所以列表的开头是Excellent,底部是Totaled。然后我将其放入ListView

我的 Firebase 结构: My Firebase structure

我的查询:FirebaseFirestore.instance.collection('bikes').snapshots();

我尝试按照this post 的指导进行操作,但无济于事。我在下面按标题长度排序的非常简单的测试似乎没有对任何内容进行排序(我将排序传递给一个函数,因为排序仅在用户单击按钮时进行)。

AsyncSnapshot<QuerySnapshot<Object?>> sortSnapshot(
      AsyncSnapshot<QuerySnapshot<Object?>> snapshot) {
    if (sortList == true) {
        snapshot.data!.docs.sort((a, b) => a['Name'].length.compareTo(b['Name'].length));
    }
    return snapshot;
}

【问题讨论】:

    标签: firebase flutter sorting dart google-cloud-firestore


    【解决方案1】:

    我不认为排序部分是您的问题。以下代码使用您上面提供的相同方法按Name 的长度对项目进行排序,然后按条件排序:

    void main() {
      final conditions = {
        'Excellent': 0,
        'Great': 1,
        'Good': 2,
        'Fair': 3,
        'Poor': 4,
        'Totaled': 5,
      };
    
      final docs = [
        {'Name': 'Argon', 'Condition': 'Great'},
        {'Name': 'Baum', 'Condition': 'Good'},
        {'Name': 'Canyon', 'Condition': 'Excellent'},
        {'Name': 'Davidson', 'Condition': 'Totaled'},
        {'Name': 'Erickson', 'Condition': 'Fair'},
        {'Name': 'Focus', 'Condition': 'Poor'},
      ];
    
      docs.sort((a, b) => a['Name']!.length.compareTo(b['Name']!.length));
    
      print(docs);
    
      docs.sort((a, b) =>
        conditions[a['Condition']]!.compareTo(conditions[b['Condition']]!));
    
      print(docs);
    }
    

    我认为对正在发生的事情的更可能的解释是,您没有通过调用 setState 或类似的方式来更新 UI。或者,您的 sortList 变量可能已分配给 false。或者,您可能没有正确将该函数注册为上述按钮按下的回调。这里确实没有足够的上下文可以肯定地说,但我真的不认为你的排序代码是这里的问题。

    编辑。多看几眼之后。您为什么要四处走动并尝试更新 AsyncSnapshot 对象? documentation 表明这个类是不可变的。我假设在这个对象上调用.data 每次调用该方法时都会生成数据,而不是返回一个可变引用(否则该类不可能是不可变的)。

    基本上我认为您需要做的是将snapshot.data!.docs 保存到一个变量中,然后对其进行排序并返回,而不是返回AsyncSnapshot

    【讨论】:

    • 我传递它只是为了释放我的小部件树中的一些空间。也有助于过滤......基本上我的操作顺序是:1)使用任何添加的过滤器进行查询,2)对返回的查询进行排序。但是,我没有意识到它是不可变的......这有点令人担忧,也许可以解释为什么我的函数没有发生任何事情。我会尝试您将其保存为变量并将其传回的建议!这有点令人困惑,因为快照有很多我并不真正需要的额外信息。我必须深入挖掘实际的列表对象才能找到相关字段。
    【解决方案2】:

    解决方案:

    对于将来遇到此问题的任何人:mmcdon20 的答案是正确的。事实证明 AsyncSnapshot 确实是不可变的。尝试对其进行排序时,我没有收到任何警告或错误(这有点烦人),但这是有道理的。它无法改变,所以它没有改变。

    无论如何,我最终将排序功能修改如下:

    我的查询:FirebaseFirestore.instance.collection('bikes').snapshots();

    提取可变列表进行排序:

    var snapList = snapshot.data!.docs.toList(); // <-- Mutable List object
    var posts = sortSnapshot(snapList);          // <-- Function that sorts
    

    我的排序功能:

    List<QueryDocumentSnapshot<Object?>> sortSnapshot(
          List<QueryDocumentSnapshot<Object?>> snapList) {
        if (sortString == 'Sort by: Distance') {
          // Grab lat/lon
          // Do distance calculation via Haversine formula
          // Sort by distance
        } else if (sortString == 'Sort by: Condition') {
          snapList.sort((a, b) => compareCondition(a['Condition'], b['Condition']));
        }
        return snapList;
      }
    

    我还没有实现按距离排序,但你明白了。对于按条件排序,这是我的比较器:

    int compareCondition(String a, String b) {
        // Order: Excellent, Great, Good, Fair, Poor, Totaled
        if (a == b) return 0;
        switch (a) {
          case "Excellent":
            return -1;
          case "Great":
            if (b == 'Excellent') return 1;
            return -1;
          case "Good":
            if ((b == 'Excellent') || (b == 'Great')) return 1;
            return -1;
          case "Fair":
            if ((b == 'Excellent') || (b == 'Great') || (b == 'Great')) return 1;
            return -1;
          case "Poor":
            if ((b == 'Excellent') ||
                (b == 'Great') ||
                (b == 'Great') ||
                (b == 'Fair')) return 1;
            return -1;
          case "Totaled":
            if ((b == 'Excellent') ||
                (b == 'Great') ||
                (b == 'Great') ||
                (b == 'Fair') ||
                (b == 'Poor')) return 1;
            return -1;
        }
        return -1;
      }
    

    这会正确排序列表,然后我可以使用我的posts List 对象在我的ListView 中生成我的ListTiles

    感谢mmcdon20,希望有一天这对某人有所帮助!

    【讨论】:

      猜你喜欢
      • 2012-11-30
      • 1970-01-01
      • 1970-01-01
      • 2022-07-12
      • 1970-01-01
      • 2021-12-04
      • 2021-11-13
      • 1970-01-01
      • 2021-07-26
      相关资源
      最近更新 更多