🌟

備忘録04 Flutter Firestore DatabaseへのCRUD処理

2024/07/02に公開

概要

firebaseのDatabaseへのCRUD処理について記録する。

CRUD処理とは

CRUD処理とはデータベースへの
・Create(作成):新しいデータの作成
・Read(参照):既存のデータの読み取り
・Update(更新):既存のデータの更新
・Delete(削除):既存のデータの削除
のことである。

事前準備

  1. firebaseと紐付け
  2. パッケージのインストール

firebaseと紐付けは以下の記事でやり方を載せているため、そっちを参照
https://zenn.dev/programmer_1484/articles/8f0cee3cfd5dc2

パッケージは「firebase_core」と「cloud_firestore」をインストールする。
firebase_coreはFirebaseへの接続を可能にするためのパッケージ(プラグイン)で
cloud_firestoreはFirebaseのDateBaseへの操作を可能にするためのパッケージ(プラグイン)の認識。間違ってたらご指摘お願いします。

以下コマンドでパッケージをインストールする。

flutter pub add firebase_core
flutter pub add cloud_firestore
pubspec.yaml
firebase_core: ^2.24.2
firebase_auth: ^4.16.0

もし以下エラーが出た場合は、Podfileを修正したり、再起動したら治った。
ここも今後エラーとして残していきたい。

firebaseexception ([cloud_firestore/unknown] unable to establish connection on channel.)
Podfile
# Uncomment this line to define a global platform for your project
 platform :ios, '11.0' # ここのコメントアウトを外す。その後pod installを流す。

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
  'Debug' => :debug,
  'Profile' => :release,
  'Release' => :release,
}

コードの実装

今回はコレクション名が「collections」のデータを操作する。
正直独学なので、正しいか微妙なため、ご了承ください。
実装は、TopページとListページの二つで構成。

main.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:testapp/firebase_options.dart';
import 'package:testapp/select/listpage.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const TopPage(),
    );
  }
}

FirebaseAuth auth = FirebaseAuth.instance;

class TopPage extends StatelessWidget {
  const TopPage({
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('CRUD処理'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () {
                  // ドキュメントIDを自動発番
                  FirebaseFirestore.instance
                      .collection('collections')
                      .add({'column1': '登録処理実施完了(ID自動発番)'});

                  // ドキュメントIDを指定して登録
                  FirebaseFirestore.instance
                      .collection('collections')
                      .doc('create')
                      .set({'column1': '登録処理実施完了(ID指定)'});
                  Navigator.of(context).push(
                    PageRouteBuilder(
                      pageBuilder: (context, animation, secondaryAnimation) {
                        return const ListPage();
                      },
                    ),
                  );
                },
                child: const Text('登録')),
            ElevatedButton(
                onPressed: () {
                  // ドキュメントIDを指定して更新
                  FirebaseFirestore.instance
                      .collection('collections')
                      .doc('create')
                      .update({'column1': '更新処理完了'});

                  Navigator.of(context).push(
                    PageRouteBuilder(
                      pageBuilder: (context, animation, secondaryAnimation) {
                        return const ListPage();
                      },
                    ),
                  );
                },
                child: const Text('更新')),
            ElevatedButton(
                onPressed: () {
                  // ドキュメントIDを指定して削除
                  FirebaseFirestore.instance
                      .collection('collections')
                      .doc('create')
                      .delete();
                  Navigator.of(context).push(
                    PageRouteBuilder(
                      pageBuilder: (context, animation, secondaryAnimation) {
                        return const ListPage();
                      },
                    ),
                  );
                },
                child: const Text('削除')),
          ],
        ),
      ),
    );
  }
}

listpage.dart
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

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

  @override
  _ListPageState createState() => _ListPageState();
}

class _ListPageState extends State<ListPage> {
  late Future<QuerySnapshot> _futureCollections;

  @override
  void initState() {
    super.initState();
    _futureCollections =
        FirebaseFirestore.instance.collection('collections').get();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('参照結果'),
      ),
      body: FutureBuilder<QuerySnapshot>(
        future: _futureCollections,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            return const Center(child: Text('データ取得に失敗しました'));
          } else if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
            return const Center(child: Text('データはありません'));
          } else {
            final data = snapshot.data!.docs;
            return ListView.builder(
              itemCount: data.length,
              itemBuilder: (context, index) {
                final collection = data[index];
                return ListTile(
                  title: Text(collection['column1']),
                  subtitle: Text(collection.id),
                );
              },
            );
          }
        },
      ),
    );
  }
}

Create(登録)

登録処理はドキュメントIDを自動発番する方法とドキュメントIDを指定して登録する方法がある。
例えばアカウント作成したときのユーザーIDをドキュメントIDとして設定して、
それに紐づいたユーザー情報などを登録できたりする。

listpage.dart
// ドキュメントIDを自動発番
FirebaseFirestore.instance
    .collection('collections')
    .add({'column1': '登録処理実施完了(ID自動発番)'});

// ドキュメントIDを指定して登録
FirebaseFirestore.instance
    .collection('collections')
    .doc('create')
    .set({'column1': '登録処理実施完了(ID指定)'});

Update(更新)

ドキュメントIDを指定して、対象のカラムを更新する。

main.dart
// ドキュメントIDを指定して更新
FirebaseFirestore.instance
    .collection('collections')
    .doc('create')
    .update({'column1': '更新処理完了'});

Delete(削除)

ドキュメントIDを指定して、対象のデータを削除する。

main.dart
// ドキュメントIDを指定して削除
FirebaseFirestore.instance
    .collection('collections')
    .doc('create')
    .delete();

Read(参照)

firebaseからデータを参照する。今回は何も条件をつけずに全件取得。

main.dart
// ドキュメントIDを指定して削除
@override
void initState() {
    super.initState();
    _futureCollections =
    FirebaseFirestore.instance.collection('collections').get();
}

↓登録後

↓更新後

↓削除後

最後に

実際はもっとカラム数(フィールド)は多いし、参照する条件とか並び替えとかがあるんで、
今後はそちらも上げていきたい

Discussion