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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 06:24:04