FlutterでFieldValue.arrayUnion&arrayRemoveを使った時のメモ


はじめに

Flutterを使ってネイティブアプリを作っているが、Widgetの使い方やFirestoreとのデータ連携の仕方など、コードの書き方が分からずそれなりに苦労している。
一旦分かってしまえばかなり高速でアプリ開発ができそうなので、使い方やコードの書き方のメモを残しておく。
今回はタイトルにある通り、Firestoreを操作する際のarray型のデータ更新についてメモを残す。

Flutterの実行環境

  • Ubuntu 18.04LTS(GCP上)
  • Flutter 1.22.6
  • Dart 2.10.5
  • Android Studio 4.1.2
  • VScode 1.53.0   

メモ内容

Firestoreでarray型のフィールドを作成しておき、それらに対してFieldValue.arrayUnion & arrayRemoveを使い要素の追加、削除を試してみた。
単純なarray型と、arrayの中がさらにMAP型になっている2つのパターンで、コードの書き方を確認してみる。

Firestoreの中のデータ構造は以下の様な感じで準備

以下のmain.dartを作成してflutter runを実行

main.dart
// 必要パッケージのインポート
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

void main() {
  runApp(testApp());
}

// メインで呼び出されるクラス。
class testApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final db_ope = CloudFirestore_update();

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: Text("ホーム"),
        ), // appBar プロパティに AppBar Widget を追加
        body: Center(child: Text("Firestoreの連携テスト")),

        // 右下にアクションボタンを設置して、ここをクリックすると、今回試したい機能を実行できる仕組み。
        floatingActionButton: Container(
          margin: EdgeInsets.only(bottom: 10.0), // ボタンの配置
          width: 40.0,
          height: 40.0,
          child: FloatingActionButton(
            //tooltip: 'Increment',
            child: Icon(Icons.add),
            onPressed: () =>
                // 以下の4つの内、どれかのコメントアウトを外して実行結果を確認してみる。
                 db_ope.add_element_simple('test_document'),
                // db_ope.delete_element_simple('test_document'),
                // db_ope.add_element_map('test_document'),
                // db_ope.delete_element_map('test_document'),
          ),
        ),
      ),
    );
  }
}

// 今回FirestoreのUpdate操作を行うためのクラスを作成。
class CloudFirestore_update {
  static const String target_collection = 'test_collection';

  // arrayUnionを使った更新(要素追加)
  void add_element_simple(String document_id) {
    String colc = target_collection;

    Firestore.instance.collection(colc).document(document_id).updateData({
      'array_field1':
          FieldValue.arrayUnion(['add-data1-1', 'add-data1-2', 'add-data1-2'])
    });
  }
  // ⇒ 2番目と3番目は要素の中身が同じため追加されるデータは2つのみ!


  // arrayRemoveを使った更新(要素削除)
  void delete_element_simple(String document_id) {
    String colc = target_collection;

    Firestore.instance.collection(colc).document(document_id).updateData({
      'array_field1': FieldValue.arrayRemove(['data1-1', 'add-data1-2'])
    });
  }
  // ⇒ 試しに中身が同じ要素のデータ2つ用意すると、両方とも消えてしまう!


  // arrayUnionを使った更新(要素追加) ※arrayの中がMAP型
  void add_element_map(String document_id) {
    String colc = target_collection;

    Firestore.instance.collection(colc).document(document_id).updateData({
      'array_field2': FieldValue.arrayUnion([
        {
          'map2c': 'new_field',
          'map2d': 'new_field',
        },
      ]),
    });
  }
  // ⇒ array型の中でそもそも作成していたField構造とは関係なく要素追加が可能なため、注意が必要!


  // arrayRemoveを使った更新(要素削除)※arrayの中がMAP型
  void delete_element_map(String document_id) {
    String colc = target_collection;

    Firestore.instance.collection(colc).document(document_id).updateData({
      'array_field2': FieldValue.arrayRemove([
        {
          'map2a': 'data2-a',
          'map2b': 'data2b',
        },
      ]),
    });
  }
   // ⇒ array型の中身のMAP内の要素が完全一致していない削除されない。(逆に完全一致するものが複数ある場合は同時に消える。)
}

※Firestoreパッケージが上手く使えない場合は、こちらの記事を参考に!
 【FlutterからCloud Firestoreのデータ取得 & データ書き込み】

上記のmain.dartを実行すると、エミュレータ上では以下の様になる。

右下のアクションボタンをクリックすると、Firestoreの操作が動く。
 ※アクションボタンで呼び出されるメソッドは、main.dart内のonPressed:の部分で設定する。

備考

FieldValue.arrayRemove'を使った際、indexを利用した削除ができるかと思っていたのだが、色々試したり調べてみたがやり方が分からなかった。(そもそもできない?)
もしやり方が分かれば更新します。