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

Flutter Firestore v2各类类型withConverter的fromJson/toJson实现示例

使用Firestore v2 withConverter处理数组及全类型对象转换

核心解决:LinkedMap数组转自定义对象列表

Firestore返回的数组会以LinkedHashMap形式存在,在fromJson中需手动遍历数组,将每个LinkedMap转换为对应数据类。以下是覆盖所有常见Firestore类型的完整示例:

1. 定义数据类与Converter

先创建包含Firestore全类型的主数据类,以及嵌套对象的数据类:

import 'package:cloud_firestore/cloud_firestore.dart';

// 嵌套对象数据类
class Address {
  final String street;
  final String city;

  Address({required this.street, required this.city});

  factory Address.fromJson(Map<String, dynamic> json) {
    return Address(
      street: json['street'] as String,
      city: json['city'] as String,
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'street': street,
      'city': city,
    };
  }
}

// 主数据类:覆盖Firestore常见类型
class User {
  final String id;
  final String name;
  final int age;
  final bool isActive;
  final Timestamp createdAt;
  final GeoPoint location;
  final DocumentReference<Map<String, dynamic>>? profileRef;
  final List<Address> addresses; // 嵌套对象数组
  final List<String> hobbies; // 基础类型数组
  final List<int> scores;

  User({
    required this.id,
    required this.name,
    required this.age,
    required this.isActive,
    required this.createdAt,
    required this.location,
    this.profileRef,
    required this.addresses,
    required this.hobbies,
    required this.scores,
  });

  // fromJson:处理LinkedMap数组转换
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as String,
      name: json['name'] as String,
      age: json['age'] as int,
      isActive: json['isActive'] as bool,
      createdAt: json['createdAt'] as Timestamp,
      location: json['location'] as GeoPoint,
      profileRef: json['profileRef'] as DocumentReference<Map<String, dynamic>>?,
      // 嵌套对象数组:遍历转成Address实例
      addresses: (json['addresses'] as List)
          .map((item) => Address.fromJson(item as Map<String, dynamic>))
          .toList(),
      // 基础类型数组:直接强转
      hobbies: (json['hobbies'] as List).cast<String>(),
      scores: (json['scores'] as List).cast<int>(),
    );
  }

  // toJson:转换为Firestore可识别格式
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'age': age,
      'isActive': isActive,
      'createdAt': createdAt,
      'location': location,
      'profileRef': profileRef,
      // 对象列表转Map列表
      'addresses': addresses.map((addr) => addr.toJson()).toList(),
      'hobbies': hobbies,
      'scores': scores,
    };
  }
}

2. 搭配withConverter使用

在集合/文档引用中绑定Converter,实现自动读写转换:

// 获取带Converter的集合引用
final CollectionReference<User> usersCollection = FirebaseFirestore.instance
    .collection('users')
    .withConverter<User>(
      fromFirestore: (snapshot, _) => User.fromJson(snapshot.data()!),
      toFirestore: (user, _) => user.toJson(),
    );

// 示例:添加用户
Future<void> addUser(User user) async {
  await usersCollection.add(user);
}

// 示例:获取单个用户
Future<User?> getUser(String userId) async {
  final docSnapshot = await usersCollection.doc(userId).get();
  return docSnapshot.data();
}

// 示例:监听用户列表
Stream<List<User>> getUsersStream() {
  return usersCollection.snapshots().map((snapshot) {
    return snapshot.docs.map((doc) => doc.data()).toList();
  });
}

关键注意事项

  • 嵌套对象数组:必须遍历每个LinkedMap,调用对应数据类的fromJson,不能直接强转。
  • 基础类型数组:直接用cast<T>()即可完成转换。
  • Firestore特殊类型(Timestamp、GeoPoint、DocumentReference):可直接在fromJson/toJson中传递,Firestore会自动处理序列化。
  • 空值处理:若数组可能为null,需添加空判断,例如:
    addresses: (json['addresses'] as List?)
        ?.map((item) => Address.fromJson(item as Map<String, dynamic>))
        .toList() ?? [],
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 11:52:34