You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中Firebase嵌套Map查询问题:修复fromSnapshot方法

Firebase嵌套Map数据模型fromSnapshot方法修复求助

我为Firebase的嵌套Map数据定义了如下模型,该模型可将嵌套Map数据正常上传至Firebase(数据结构见下方截图)。现在我希望从Firebase查询数据并通过ListViewBuilder在应用中展示,但查询时出现异常,请求帮助修复模型中的fromSnapshot方法。

原模型代码

class Names {
  UserInformationModelMap names;
  Names({
    required this.names,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'names': names.toMap(),
    };
  }

  factory Names.fromMap(Map<String, dynamic> map) {
    return Names(
      names: UserInformationModelMap.fromMap(
        map['names'] as Map<String, dynamic>,
      ),
    );
  }

  factory Names.fromSnapshot(DocumentSnapshot<Map<String, dynamic>> doc) {
    return Names(
      names: UserInformationModelMap.fromSnapshot(
        doc,
      ),
    );
  }
}

class UserInformationModelMap {
  WholeNameMap fullName;
  String? uid;
  UserInformationModelMap({
    required this.fullName,
    this.uid,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      uid!: fullName.toMap(),
    };
  }

  factory UserInformationModelMap.fromMap(Map<String, dynamic> map) {
    return UserInformationModelMap(
      fullName: WholeNameMap.fromMap(map['fullName'] as Map<String, dynamic>),
    );
  }

  factory UserInformationModelMap.fromSnapshot(
      DocumentSnapshot<Map<String, dynamic>> doc) {
    return UserInformationModelMap(
      fullName: WholeNameMap.fromMap(doc['fullName'] as Map<String, dynamic>),
    );
  }
}

class WholeNameMap {
  String firstName;
  String lastName;

  WholeNameMap({
    required this.firstName,
    required this.lastName,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'firstName': firstName,
      'lastName': lastName,
    };
  }

  factory WholeNameMap.fromMap(Map<String, dynamic> map) {
    return WholeNameMap(
      firstName: map['firstName'] as String,
      lastName: map['lastName'] as String,
    );
  }
}

Firebase数据结构截图

Firebase嵌套Map数据结构

查询异常截图

查询异常截图


问题分析与修复方案

问题根源

异常Bad state: No element是因为模型的fromSnapshot方法没有正确匹配Firebase的嵌套结构:

  1. Names.fromSnapshot错误地将整个文档快照直接传给UserInformationModelMap.fromSnapshot,但实际UserInformationModelMap对应的数据在文档的names字段下。
  2. UserInformationModelMap.fromMap和fromSnapshot试图直接从根节点取fullName,但实际fullName是嵌套在names字段下以uid为键的子Map中。

修正后的模型代码

class Names {
  UserInformationModelMap names;
  Names({
    required this.names,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'names': names.toMap(),
    };
  }

  factory Names.fromMap(Map<String, dynamic> map) {
    return Names(
      names: UserInformationModelMap.fromMap(
        map['names'] as Map<String, dynamic>,
      ),
    );
  }

  factory Names.fromSnapshot(DocumentSnapshot<Map<String, dynamic>> doc) {
    final data = doc.data()!;
    return Names(
      names: UserInformationModelMap.fromMap(data['names'] as Map<String, dynamic>),
    );
  }
}

class UserInformationModelMap {
  WholeNameMap fullName;
  String? uid;
  UserInformationModelMap({
    required this.fullName,
    this.uid,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      uid!: fullName.toMap(),
    };
  }

  factory UserInformationModelMap.fromMap(Map<String, dynamic> map) {
    // 从map中取出唯一的键作为uid,对应的值是fullName的Map
    final entry = map.entries.first;
    final uid = entry.key;
    final fullNameMap = entry.value as Map<String, dynamic>;
    return UserInformationModelMap(
      uid: uid,
      fullName: WholeNameMap.fromMap(fullNameMap),
    );
  }

  // 基于fromMap实现fromSnapshot,保证逻辑一致性
  factory UserInformationModelMap.fromSnapshot(DocumentSnapshot<Map<String, dynamic>> doc) {
    final data = doc.data()!;
    return UserInformationModelMap.fromMap(data['names'] as Map<String, dynamic>);
  }
}

class WholeNameMap {
  String firstName;
  String lastName;

  WholeNameMap({
    required this.firstName,
    required this.lastName,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'firstName': firstName,
      'lastName': lastName,
    };
  }

  factory WholeNameMap.fromMap(Map<String, dynamic> map) {
    return WholeNameMap(
      firstName: map['firstName'] as String,
      lastName: map['lastName'] as String,
    );
  }
}

关键修改点

  1. Names.fromSnapshot:先获取文档数据,取出names字段后再传给UserInformationModelMap.fromMap,而非直接传递整个快照。
  2. UserInformationModelMap.fromMap:遍历names下的键值对(以uid为键),取出uid和对应的fullName子Map,正确解析嵌套结构。
  3. UserInformationModelMap.fromSnapshot:调整为基于fromMap实现,保证逻辑一致性。

内容的提问来源于stack exchange,提问作者Tristaaaan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 23:58:13