(Flutter)使用Firestore数据库的CRUD操作。
#database #flutter #firebase #crud

介绍

在构建我的应用程序时,我发现了100种来自Firestorm数据库数据的方法,尤其是Internet中仍然有一些过时的信息。
在这篇文章中,我希望给出最清晰的方法来实现所有CRUD操作,尤其

我假设您已经设置了Firebase并熟悉Flutter的语法。

设置模型
首先,我建议您在Firestone内部创建该集合和“演示”文档,以掌握您将如何创建的模型。

Image description

就像您可以看到IV创建了收集动物一样,其中有几个领域。一个特别的字段是“ ID”字段,我个人喜欢使用Uniq ID Firebase自动创建每个文档,从而为其生成,这有助于避免发生冲突。我创建字段“ ID”,因此访问ID非常容易,还有其他方法可以通过调用数据库中的文档ID来访问它,但是我们不会在此处访问。有时,给予其他类型的ID是可取的,例如,当我创建一个“用户”集合时,我更喜欢将ID作为电子邮件作为电子邮件,这有助于搜索用户,尤其是如果您以后将其分组在其他集合中。 /p>

回到我们的收藏“动物”,现在我知道我的数据库中的对象看起来像什么,我会在flutter中创建模型。

为该井创建一个新文件animals_model.dart
内部井创建一个用于动物的课程,并列出创建“动物”对象的要求:

class Animal {
  String id; //id of the document inside firestore's db
  String name; // name of the animal
  int nubmer_of_legs; // nubmer of legs the animals has
  DateTime creation_date; // when the document was added tot he db

  Animal ({
    this.id = '',
    required this.name,
    required this.nubmer_of_legs,
    required this.creation_date,
  });}

此类将保存对象的模型。该模型将定义将保存到Firestore的所有必要数据。
因此,现在我们已经可以创建一个类型的“动物”对象,但是我们需要将其添加到数据库中。为此,将成为createAnimalDoc方法,但是在此之前,我们需要可以将对象数据转换为JSON并从JSON转换。

  Map<String, dynamic> toJson() => {
        'id': id,
        'name': name,
        'nubmer_of_legs': nubmer_of_legs,
        'creation_date': creation_date,
      };

  static Animal fromJson(Map<String, dynamic> json) => Animal(
        id: json['id'],
        name: json['name'],
        nubmer_of_legs: json['nubmer_of_legs'],
        creation_date: (json['creation_date'] as Timestamp).toDate(), // import 'package:cloud_firestore/cloud_firestore.dart';
      );

toJson()获取动物对象数据并将其放入JSON格式,以便Firestone可以理解,fromJson映射所有字段,并获取数据并将其放入模型构建器变量中,以便我们可以在代码中访问它。

创建
在所有这些设置之后 要在firebase中创建一个新文档,我们只需创建createAnimalDoc的方法,如以下内容:

  Future createAnimalDoc(String name, int nubmer_of_legs, DateTime creation_date) async {
    final newDocAnimal = FirebaseFirestore.instance.collection('groups').doc();
    final animal = Animal(
        name: name,
        id: newDocAnimal.id,
        nubmer_of_legs: nubmer_of_legs,
        creation_date: creation_date);
    await newDocAnimal.set(animal.toJson());
  }

在此处,我们将所有变量都放入函数中,但是如果您使用控制器,也可以在此处列出它们,如果您使用了某种形式。
如果我要创建一个带有特定ID的新文档,则将其输入...doc('ENTER ID');

阅读
在我看来,阅读是用Flutter+Firestore的Crud操作中最通用的。这是因为您可能会从数据库中请求所有不同的数据。显然,您不会调用您拥有的所有数据,而只能与您的用例相关。列出了一些示例,以及如何在代码中求解/处理它们。
在开始之前,有一件事要记住,要在flutter中显示该数据,必须使用窗口小部件FutureBuilder()StreamBuilder()。本质上,您需要请求数据并等待到达,这些小部件可以做到这一点,同时使您能够检查数据是否存在,是否存在错误或是否到达数据以及该如何处理。 br> FutureBuilder()StreamBuilder()之间的区别在于,FutureBuilder()在调用小部件时一次要求数据快照,等待它然后显示它。它的问题是,如果要更改数据,它才会知道它,直到再次调用(如果您刷新页面或其他内容)。另一方面,StreamBuilder()请求流并连续将信息发送到页面。因此,如果数据在数据库中更改,则该页面也将在页面内部进行更新。
您需要的东西可以判断什么。如果一个快照就足够了,并且您不希望信息更改,则将FutureBuilder()用作应用程序更轻,并更少对数据库进行调用。如果需要实时更新信息,那么StreamBuilder()是您的家伙。

让我们看看如何使用在我们的代码中,在此示例中,我使用StreamBuidler()
首先创建一个空页面

import 'package:flutter/material.dart';

class AnimalsPage extends StatefulWidget {
  const AnimalsPage({super.key});

  @override
  State<AnimalsPage> createState() => _AnimalsPageState();
}

class _AnimalsPageState extends State<AnimalsPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(),
    );
  }
}

现在生病的呼叫方法,将“管道”变成firestore:

    Stream<List<Animal>> fetchAnimals() {
    return FirebaseFirestore.instance
        .collection('animals')
        .snapshots()
        .map((snapshot) => snapshot.docs
            .map((doc) => Animal.fromJson(doc.data()))
            .toList());
  }

现在生病了StreamBuilder()

  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: StreamBuilder<List<Animal>>(
          stream: fetchAnimals(), // feed our stream to the stream builder
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              final animals = snapshot.data!;
              return ListView.builder(
                itemCount: animals.length,
                itemBuilder: (context, index) {
                  return animalTile(animals[index]);
                }
                );
            } else if (snapshot.hasError) {
              return Text('Something went wrong!');
            } else {
              return Text('Something went wrong!');
            }
          },
        ),
      ),
    );
  }

您可以查看是否检查快照的数据是否存在,这对于调试不起作用。
最后,我们需要构建将显示信息的瓷砖。我喜欢在同一文件中使用一个单独的小部件进行操作:

Widget animalTile(Animal animal) => ListTile(
        title: Container(
          height: 50,
          width: 50,
          child: Text(animal.name),
        ),
      );

现在我们可以从数据库中请求有关收集动物的任何信息。

好吧,我们如何使用futureBuilder()做到这一点?本质上相同的方式:

  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: FutureBuilder<List<Animal>>(
          future: fetchAnimals(),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              final animals = snapshot.data!;
              return ListView.builder(
                  itemCount: animals.length,
                  itemBuilder: (context, index) {
                    return animalTile(animals[index]);
                  });
            } else if (snapshot.hasError) {
              return Text('Something went wrong!');
            } else {
              return Text('Something went wrong!');
            }
          },
        ),
      ),
    );
  }

  Future<List<Animal>> fetchAnimals() async {
    var collectionSnapshot =
        await FirebaseFirestore.instance.collection('animals').get();

    return collectionSnapshot.docs.map((doc) => Animal.fromJson(doc.data())).toList();
  }

方法fetchAnimals()需要异步等待快照从数据库到达。

特殊情况:

  • 当您想从整个集合中获取特定文档时,您可以调用.collection.doc(document_id)

  • 如果要搜索具有特定字段的文档,则可以使用.where()实现此目的,请在official documentaion中进行更多信息。

更新
这很简单,您可以在文档中获得,然后只需致电.update()
示例:

FirebaseFirestore.instance.collection('animals').doc('DOC_ID').update({
'FIELD1': 'NEW_DATA',
'FIELD2': 'NEW_DATA',
});

删除
与更新相同,您可以在文档中获得,然后只需致电.delete()
示例:
FirebaseFirestore.instance.collection('animals').doc('DOC_ID').delete();

希望这能提供更多有关该主题的最新信息,请记住还有其他方法可以通过Firestore处理CRUD功能,这只是我的方式。

-t