Flutter从Firestore读取数据报错:Bad state: field不存在
Flutter Firestore 字段读取错误排查
开发Flutter应用时,从Firestore读取imgUrl、title、desc、organizer字段时,持续报错:
Bad state: field does not exist within the DocumentSnapshotPlatform
已检查字段拼写、顺序,确认Firestore字段设置无误,但问题未解决。以下是相关代码及问题分析:
News类
import 'package:myfuji/screens/CrudMethods.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'CrudMethods.dart'; import 'add_blog.dart'; class News extends StatefulWidget { @override _NewsState createState() => _NewsState(); } class _NewsState extends State<News> { CrudMethods crudMethods = CrudMethods(); late QuerySnapshot blogSnapshot; @override void initState() { crudMethods.getData().then((result) { blogSnapshot = result; setState(() {}); }); super.initState(); } Widget blogsList() { return ListView.builder( padding: const EdgeInsets.only(top: 24), itemCount: blogSnapshot.docs.length, itemBuilder: (context, index) { return BlogTile( organizer: blogSnapshot.docs[index].get('Organizer'), desc: blogSnapshot.docs[index].get('desc'), imgUrl: blogSnapshot.docs[index].get('imgUrl'), title: blogSnapshot.docs[index].get('title'), ); }, ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Events"), ), body: Container( child: blogSnapshot != null ? blogsList() : const Center( child: CircularProgressIndicator(), )), floatingActionButton: FloatingActionButton( child: const Icon(Icons.add), onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => AddBlog())); }, ), ); } } class BlogTile extends StatelessWidget { final String imgUrl, title, desc, organizer; const BlogTile( {required this.organizer, required this.desc, required this.imgUrl, required this.title}); @override Widget build(BuildContext context) { return Container( margin: const EdgeInsets.only(bottom: 24, right: 16, left: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( child: ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(8)), child: Image.network( imgUrl, width: MediaQuery.of(context).size.width, fit: BoxFit.cover, height: 200, ), ), ), const SizedBox(height: 16), Text( title, style: const TextStyle(fontSize: 17), ), const SizedBox(height: 2), Text( '$desc - By $organizer', style: const TextStyle(fontSize: 14), ) ], ), ); } }
AddBlog类
import 'dart:io'; import 'package:myfuji/screens/CrudMethods.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:random_string/random_string.dart'; class AddBlog extends StatefulWidget { @override _AddBlogState createState() => _AddBlogState(); } class _AddBlogState extends State<AddBlog> { late File selectedImage; final picker = ImagePicker(); bool isLoading = false; CrudMethods crudMethods = new CrudMethods(); Future getImage() async { final pickedFile = await picker.getImage(source: ImageSource.gallery); setState(() { if (pickedFile != null) { selectedImage = File(pickedFile.path); } else { print('No image selected.'); } }); } Future<void> uploadBlog() async { if (selectedImage != null) { setState(() { isLoading = true; }); Reference firebaseStorageRef = FirebaseStorage.instance .ref() .child("events/") .child("${randomAlphaNumeric(9)}.jpg"); final UploadTask task = firebaseStorageRef.putFile(selectedImage); var imageUrl; await task.whenComplete(() async { try { imageUrl = await firebaseStorageRef.getDownloadURL(); } catch (onError) { print("Error"); } print(imageUrl); }); Map<String, dynamic> blogData = { "imgUrl": imageUrl, "Organizer": authorTextEditingController.text, "title": titleTextEditingController.text, "desc": descTextEditingController.text }; crudMethods.addData(blogData).then((value) { setState(() { isLoading = false; }); Navigator.pop(context); }); } } TextEditingController titleTextEditingController = new TextEditingController(); TextEditingController descTextEditingController = new TextEditingController(); TextEditingController authorTextEditingController = new TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Create Blog"), actions: [ GestureDetector( onTap: () { uploadBlog(); }, child: Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Icon(Icons.file_upload)), ) ], ), body: isLoading ? Container( child: Center( child: CircularProgressIndicator(), )) : SingleChildScrollView( child: Container( margin: EdgeInsets.symmetric(horizontal: 16), child: Column( children: [ GestureDetector( onTap: () { getImage(); }, child: selectedImage != null ? Container( height: 150, margin: EdgeInsets.symmetric(vertical: 24), width: MediaQuery.of(context).size.width, child: ClipRRect( borderRadius: BorderRadius.all(Radius.circular(8)), child: Image.file( selectedImage, fit: BoxFit.cover, ), ), ) : Container( height: 150, decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.all(Radius.circular(8))), margin: EdgeInsets.symmetric(vertical: 24), width: MediaQuery.of(context).size.width, child: Icon( Icons.camera_alt, color: Colors.white, ), ), ), TextField( controller: titleTextEditingController, decoration: InputDecoration(hintText: "enter title"), ), TextField( controller: descTextEditingController, decoration: InputDecoration(hintText: "enter desc"), ), TextField( controller: authorTextEditingController, decoration: InputDecoration(hintText: "enter author name"), ), ], )), ), ); } }
CrudMethods类
import 'package:cloud_firestore/cloud_firestore.dart'; class CrudMethods { Future<void> addData(blogData) async { print(blogData); FirebaseFirestore.instance .collection("events/") .add(blogData) .then((value) => print(value)) .catchError((e) { print(e); }); } getData() async { return await FirebaseFirestore.instance.collection("events/").get(); } }
Firestore字段说明
Firestore中存储的字段为:imgUrl、title、desc、organizer(全小写开头)
问题原因及解决方案
1. 字段名大小写不匹配
上传数据时(AddBlog类)使用的字段名是"Organizer"(大写O开头),但Firestore中实际存储的是organizer(小写o开头),读取时(News类)又用了'Organizer',导致部分文档找不到对应字段。
解决:统一字段名大小写,将AddBlog中的"Organizer"改为"organizer",同时News类中读取时改为blogSnapshot.docs[index].get('organizer')。
2. 集合路径错误
CrudMethods类中集合路径写为"events/"(带末尾斜杠),Firebase会将其解析为events集合下的空路径子集合,导致读取/写入的不是目标集合。
解决:去掉路径末尾的斜杠,改为collection("events"),修改后的CrudMethods:
import 'package:cloud_firestore/cloud_firestore.dart'; class CrudMethods { Future<void> addData(blogData) async { print(blogData); FirebaseFirestore.instance .collection("events") .add(blogData) .then((value) => print(value)) .catchError((e) { print(e); }); } getData() async { return await FirebaseFirestore.instance.collection("events").get(); } }
3. 增加字段读取容错(可选)
为避免因字段缺失导致崩溃,可以使用带默认值的读取方式:
organizer: blogSnapshot.docs[index].get('organizer', defaultValue: 'Unknown'),
或者先检查字段是否存在:
organizer: blogSnapshot.docs[index].data().containsKey('organizer') ? blogSnapshot.docs[index].get('organizer') : 'Unknown',
内容的提问来源于stack exchange,提问作者Abraham Esparza
相关产品推荐
相关产品推荐

