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型になっている２つのパターンで、コードの書き方を確認してみる。

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

![Qiita-No030_img01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/bc8d687c-6c19-5a02-72fc-c99d23675be3.jpeg)

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

```dart: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番目は要素の中身が同じため追加されるデータは２つのみ！


  // 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'])
    });
  }
  // ⇒ 試しに中身が同じ要素のデータ２つ用意すると、両方とも消えてしまう！


  // 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のデータ取得 ＆ データ書き込み】](https://qiita.com/smiler5617/items/8dcf720f5477a5f4b7d7)

#### 上記の`main.dart`を実行すると、エミュレータ上では以下の様になる。
右下のアクションボタンをクリックすると、Firestoreの操作が動く。
　※アクションボタンで呼び出されるメソッドは、`main.dart`内の`onPressed:`の部分で設定する。
![Qiita-No031_img02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/dcac6d8e-d971-2810-2638-391cfc953284.jpeg)

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