Flutter:将Firebase Realtime数据库快照解析为列表

时间:2020-01-11 16:21:22

标签: flutter dart

我尝试搜索其他问题,但是与此类似的唯一问题是在JavaScript中给出了答案,而不是Dart / Flutter。我正在尝试以List<BaseModel>

的形式从Firebase实时数据库中获取一个列表到应用程序中

到目前为止,与我在网上搜索的内容相去甚远,我认为DataSnapshot的结果是我可以解析的地图,因此我尝试了一下,但遇到了以下错误:List<dynamic>' is not a subtype of type 'Map<dynamic, dynamic>

我的代码:

Future<List<BaseModel>> getList(
    {DatabaseReference query, Models modelType}) async {
  List<BaseModel> list = new List();
  DataSnapshot snap = await query.once();
  Map<String, dynamic> json = Map.from(snap.value);
  json.forEach((key, value) {
    list.add(BaseModel(model: modelType, key: key, snapshot: value));
  });
  return list;
}

奇怪的是,即使我尝试解析非列表模型,我也会遇到相同的错误。

我的数据库结构如下:

enter image description here

更新

BaseModel:

abstract class BaseModel {
  factory BaseModel({Models model, String key, Map map}) {
    switch (model) {
      case Models.MyModel:
        return MyMod.fromSnapshot(key: key, map: map);
        break;
      default:
        throw ("Not a valid model.");
    }
  }
}

MyModel:

MyModel.fromSnapshot({String key, Map map}) {
  _id = key;
  _title = map['title'];
}

我的Firebase查询只是带有.child("Root")的数据库引用

2 个答案:

答案 0 :(得分:0)

我也有类似的经历,其中snapshot.value有时返回一个列表,有时返回一个Map。我搜索了很长时间,但没有运气,但我想出了一种解决方法。 我怀疑问题是由使用值为零的记录键引起的,因此我在将每个键添加到db之前将其添加了100,然后在读取并处理记录时将其减去。问题消失了,然后我总是得到了地图。 从那以后,我已经看到了这种现象的原因,它证实了零键值是罪魁祸首,但是不幸的是我没有保存链接。我认为它是在Firebase博客之一上。 我认为0记录返回一个列表,而具有正值的记录返回一个Map。 无论如何,请尝试添加100的技巧,然后看看会有所帮助。如果有帮助,请支持我。...我认为您不需要添加或删除100的代码。:-)

找到这篇文章,Firebase正在根据快照内容决定是否应该渲染数组或地图:https://firebase.googleblog.com/2014/04/best-practices-arrays-in-firebase.html?m=1

更新:

对不起,我的“从0开始”理论是一条红鲱鱼。

此行为的关键(粗体中的位)在Firebase博客的一部分(上面的链接)中指出:

但是,当您需要帮助在Firebase中存储阵列的人员时, 调用.val()或使用REST api读取数据,如果数据看起来像 一个数组,Firebase会将其呈现为一个数组。

尤其是,如果所有键都是整数,并且一半以上 0和对象中最大键之间的键为非空 值,然后Firebase会将其呈现为数组。 重要的是要记住。

///我们发送此['a','b','c','d','e'] // Firebase存储此{0: 'a',1:'b',2:'c',3:'d',4:'e'}

//由于键是数字键和顺序键,//如果我们查询数据, 我们得到这个['a','b','c','d','e']

//,但是,如果我们随后删除a,b和d,则//它们不再 大多是顺序的,所以//我们不会返回数组{2:'c',4:'e'} 您目前无法更改或阻止此行为。

我现在已经通过设置一个如下图所示的db节点来对此进行了测试。我使用snapshot.valuesnapshot.value is List测试了snapshot.value is Map中返回的内容,它们都返回true或false。

仅存在节点0、1和3时,Firebase RTDB会很高兴地在snapshot.value中返回一个列表。当我添加数据不一致的节点4和6时,它决定是时候返回Map了。 :-)

因此,快速的解决方案是使用is List和/或is Map测试snapshot.value的内容,然后进行相应的处理,否则请重新考虑您的密钥...事实是问题是顺序的或接近顺序的(有间隙),但子结构相同。

enter image description here

答案 1 :(得分:0)

我找到了解决方法!

我的新代码:

Future<List<BaseModel>> getList({DatabaseReference query, Models modelType}) async {
  List<BaseModel> list = new List();
  DataSnapshot snap = await query.once();
  List<dynamic> resultList = snap.value;
  for(var i = 0; i < resultList.length; i++) {
    Map<dynamic, dynamic> map = Map.from(resultList[i]);
    list.add(BaseModel(model: modelType, key: i.toString(), snapshot: map));
  }
  return list;
}

假设您从模型的.fromMap(yourMap)构造函数方法中解析值,这应该可以工作。像_title = yourMap['key'];