FlutterでMongoDB AtlasとFirebase Cloud Messageを使って通知機能を作る

# 実現したいこと
Flutterアプリ（Android）で通知機能を作りたい！
どうすればいい？
Firebase Cloud Message（以後FCM）を使えばできそう！
MongoDB Atlasをクラウドサーバーとして使ってるけどできるか？
連携機能があって簡単にできそう！[ドキュメント]("https://www.mongodb.com/docs/atlas/app-services/reference/push-notifications/")もあるし参考にして...
あーでもこれ非推奨になってて、2024年には完全にサポート終了するのか、

じゃあMongoDBのTriggerを使う方法でやってみよう！
**これが ~~サーバーサイドをあまり知らない自分にとって~~ つらかったのでまとめます**

# まず準備
本題以外は軽く飛ばします。そして、サーバーのデータなどはある前提です。

<dl>
    <dt>Step1</dt>
    <dd>Firebaseのプロジェクトを準備します。</dd>
    <dt>Step2</dt>
    <dd> Firebase Admin SDKをMongoDB Atlasに追加します。Triggersの<strong>Add Dependencies</strong>ボタンからfirebase-adminを追加します。 </dd>
  <dt>Step3</dt>
  <dd> Firebaseのプロジェクトから <code>projectId</code> <code>clientEmail</code> <code>privateKey</code> を取得します。ここではファイルを置く方法もあるのですが、自分の力ではできなかったので、jsonファイルを出力して、その中のデータを直で張り付けるごり押し方法で実装するために準備します。</dd>
    <dt>Step4</dt>
    <dd> FlutterでFirebaseを使えるように初期化をして、任意のタイミングで使用したいコレクションのドキュメントに、生成したトークンを配置します。 </dd>
    <dt>Step5</dt>
    <dd> ここまで出来たらMongoDB AtlasのTriggersから<strong>Add Trigger</strong>でTriggerを実装していきます。 </dd>
</dl>

# いざ実装
Atlas Triggerの設定
![Untitl11ed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1408220/2eda3456-f3d3-d2e4-25b0-376adef4f3e5.png)
![Untitle22d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1408220/28287651-d9f2-1875-9210-4f85a07e71b4.png)
![Untitle33d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1408220/0e819cb8-6a51-c6f3-e575-4a92f424da2d.png)

Triggerのコード
```javascript:onPushNotification.js
exports = async function(changeEvent) {
  // データベースからデータ取得
  const serviceName = 'Cluster';
  const database = 'Database';
  const collection = context.services.get(serviceName).db(database).collection('Collection');

  // ObjectID型でIDを取得
  const docId = changeEvent.documentKey._id;
  console.log(docId);
  
  // デバイスに登録されたトークンを使うのでデバイスを取得
  const device = await collection.findOne({ _id: docId});
  
  // FCMの初期化
  const admin = require('firebase-admin');
  admin.initializeApp({
    credential: admin.credential.cert({
      projectId: 'ProjectID',
      clientEmail: 'ClientEmail',
      privateKey: ('PrivateKey').replace(/\\n/g, '\n'),
    }),
  });

  // コレクションのドキュメントからデータを取得
  const token = device.token;
  console.log(token);

  // 通知に送るメッセージ
  const message = {
    notification: {
      body: '通知のメッセージ',
      title: '通知のタイトル'
    },
    token: token
  };
  
  // メッセージを送信し、そのレスポンスを処理する
  admin.messaging().send(message)
    .then((response) => {
      // Response is a message ID string.
      console.log('Successfully sent message:', response);
    })
    .catch((error) => {
      console.log('Error sending message:', error);
    });
};
```
このままじゃ動かないので、下の解説をもとにそれぞれ変更してください。

## かんたんに解説
### 任意の文字列に変更してほしいところ
`Cluster` `Database` `Collection`
これらはMongoDB Atlasのそれぞれに適応する名前に変更してください。

`ProjectID` `ClientEmail` `PrivateKey`
これらはFireabseからJsonをダウンロードすることで得られます。
方法として、Firebaseのコンソールから、
設定 -> プロジェクトの設定 -> Cloud Messaging、からサービスアカウントの管理に飛ぶと、アカウントが表示されるので、
鍵の管理 -> 鍵を追加、でJsonファイルをダウンロードしてそこから上の３つに反映させます。

`通知のメッセージ` `通知のタイトル`
ここは飛ばしたい通知の内容にしてください！

# めっちゃ参考
属性や実装場所やサービスごとに分けます
### Mongo DB
* [Push Notifications [Deprecated]]("https://www.mongodb.com/docs/atlas/app-services/reference/push-notifications/")
非推奨ですが、Atlasで簡単にFCM連携する方法が載ってる公式ドキュメントです。
* [Push Notifications Using Atlas App Services & iOS Realm SDK]("https://medium.com/realm/send-push-notifications-to-your-application-using-atlas-app-services-ios-realm-sdk-65208b63f9b5")
AtlasのTriggerのコードがメインで乗ってます。FCMのあたりは詳しく乗ってないです。
* [MongoDB Stitch の Triggers / Functions で気軽に始めるサーバレス生活]("https://tech.basicinc.jp/articles/212")
AtlasのTriggerやFunctionについて詳しく書いてあって理解がはかどります。

### Firebase
* [Flutter で Firebase Cloud Messaging クライアント アプリを設定する]("https://firebase.google.com/docs/cloud-messaging/flutter/client?hl=ja#install_the_fcm_plugin")
FlutterでFirebaseのサーバーでFCMを使う方法が載っています。トークンを生成するあたりが参考になります。
* [サーバーに Firebase Admin SDK を追加する]("https://firebase.google.com/docs/admin/setup?hl=ja")
MongoDB AtlasにFirebase Admin SDKを追加するときに参考になったり。
* [[messaging] TypeError: Value is not an object: undefined]("https://github.com/firebase/firebase-admin-node/issues/2037")
Firebase Admin SDKのバージョン関連でエラーが出るのでその参考になります。