GoogleHomeに話しかけて検索結果をブラウザに表示させる　❸FirebaseのFunctions実行時 Databaseにデータを追加する

GoogleHome(mini)を購入したので、聞き取ったキーワードから
PCのブラウザに**Googleの検索結果1位のサイトを表示**して、そのサイトの**タイトルを読み上げる**アプリを作成しました。検索したキーワードがDBに無かった場合はキーワードとURLとタイトルを登録します。
##**最終的に出来たアプリ**
![1_久慈の生うに大好き💛.png](https://qiita-image-store.s3.amazonaws.com/0/237418/0e96d2bf-3e2a-125a-dc9c-3593d237640b.png "あまちゃんの生うにをふるさと納税で毎年頂いています")
##**ワタシがやったこと**
極力Googleさんのサービスだけで完結したいなーということで、DialogflowとFirebaseを使用
Firebaseがホスティングサーバーとデータベースと関数の管理と色々サービスを担ってくれているので
全部お任せしました。
![2_ワタシがやったことjpg.png](https://qiita-image-store.s3.amazonaws.com/0/237418/ad8611c7-628d-7d79-3d09-d8805a0472cb.png "本当Firebaseって素敵なサービスです💛")


:one:　**[Dialogflowを使用して簡単なチャットボットを作成](https://qiita.com/tedkuma/items/9ceb17936c714a205a74)**
:two:　**[FirebaseのFunctions(cloud functions)を使用して、:one:で作ったボットが適切な返事するように設定](https://qiita.com/tedkuma/items/d892ec31c3cdaf35753b)**
:three: 　:two: を実行する際に**FirebaseのDatabase**にデータを追加するように設定
:four:  　:three: のデータ追加をトリガーに**FirebaseのHosting**で作成したページ(htmlファイル)にパラメータを渡し、
　　　windowopenで対象のページを開くように設定
:five:  　Google検索で一番上に表示されてるページを一発で表示させてみる(I'm feeling luckey!)
:six: 　データ登録時にページタイトルとサイトURLはオリジナルのものを保存する
　　　(webスクレイピングには**[cheerio-httpcli](https://www.npmjs.com/package/cheerio-httpcli)**を使用しました )
:seven:　 フリーのMP3データを**FirebaseのStorage**に入れてレスポンスに音声データを返す(SSML)

---
##:three: **[Firebase](https://firebase.google.com/?hl=ja)のFunctions実行時 Databaseにデータを追加する**##
![3_stage3.png](https://qiita-image-store.s3.amazonaws.com/0/237418/e42e8d4d-312e-eb82-5327-8610ad391961.png)

さて、では早速Firebaseを開いてDatabaseタブを選んでRealtime Databaseをクリック
![4_databeseいきます.png](https://qiita-image-store.s3.amazonaws.com/0/237418/d40b7787-e46b-5932-06ab-cedc1ed39d1b.png)

Realtime Database のセキュリティルールの画面でテストモードで開始を選び有効にするを押す
![5_DBセキュリティルール.png](https://qiita-image-store.s3.amazonaws.com/0/237418/58a3a2b4-0c0d-96b2-ca89-f89896c8c318.png)

するとこんな画面が出てきます。Realtime Database側の用意は出来ました。
![6_RealtimeDBの画面.png](https://qiita-image-store.s3.amazonaws.com/0/237418/c810f7db-52ff-5471-edb5-46b1090b64a4.png)

####**では、Databeseにアクセス出来るような記述をindex.jsに追加します。**####
<details><summary>前回までのindex.jsはこちら</summary><div>

~~~javascript:index.js
const functions = require("firebase-functions");//クラウド関数を作成してトリガを設定するためのFirebase SDKのクラウド関数。

exports.hoyatalk = functions.https.onRequest((request, response) => {
    const dialogflow_param = request.body.queryResult.parameters.Greeting_in_the_morning;  //Dialogflowから来てるパラメータを受けとる 

    response.setHeader("Content-Type", "application/json"); //Dialogflowに情報を返す
    response.send(
        JSON.stringify({
            "fulfillmentText": "おはようございます"
        })
    );
});
~~~
</div></details>

####**☟こちらが今回の最終的なコードです。**####

~~~javascript:index.js
const functions = require("firebase-functions");//クラウド関数を作成してトリガを設定するためのFirebase SDKのクラウド関数。

//★★ ココから(1)
const admin = require("firebase-admin");//Firebase Realtime DatabaseにアクセスするFirebase Admin SDK
admin.initializeApp(functions.config().firebase);
//★★ ココまで(1)

exports.hoyatalk = functions.https.onRequest((request, response) => {
    const dialogflow_param = request.body.queryResult.parameters.Greeting_in_the_morning;  //Dialogflowから来てるパラメータを受けとる 
    const dialogflow_user_say = request.body.queryResult.queryText; 

    const nd = new Date();
    nd.setTime(nd.getTime() + 1000*60*60*9);//UTC→JSTに変換(9h追加)
    const year = nd.getFullYear(),month = nd.getMonth()+1,day =nd.getDate(),hour = nd.getHours(),minute = nd.getMinutes();
    const time = year + "年" + month + "月" + day + "日" + hour +  "時" + minute + "分" ;

    //★★ ココから(2)
    const hoyapath = "/hoya/boya"
    admin.database().ref(hoyapath).once("value", function(snapshot) { 
        response.setHeader("Content-Type", "application/json"); //Dialogflowに情報を返す
        response.send(JSON.stringify({"fulfillmentText": "おはようございます"}));
        admin.database().ref(hoyapath).push({user_say:dialogflow_user_say, param_value:dialogflow_param , timestamp: time }) 
    });
    //★★ ココまで(2)
});
~~~

☟firebase-adminがRealtime Database のデータの読み取りと書き込みを実行する開発ツール
そのfirebase-adminを初期化(initializeApp)しています

~~~javascript:★★(1)
const admin = require("firebase-admin");//Firebase Realtime DatabaseにアクセスするFirebase Admin SDK
admin.initializeApp(functions.config().firebase);
~~~

☟hoyapath で Database のルート以下のパスを指定しています。
そしてsnapshotという機能を使ってこの関数が実行された瞬間の情報を取り出しています。
adminを使って、hoyapathにsnapshotの情報を追加してね。というのをやってます。

~~~javascript:★★(2)
const hoyapath = "/hoya/boya"
admin.database().ref(hoyapath).once("value", function(snapshot) { 
   admin.database().ref(hoyapath).push({user_say:dialogflow_user_say, param_value:dialogflow_param , timestamp: time }) 
});
~~~

今回ワタシは Database に以下の3項目を追加しています。
-user_say(ユーザーが話した言葉)　-param_value(パラメータの値)　-timestamp(実行された時間)

では、deployしてActions on GoogleのSimulatorでテストしてみます。
ルートの下にhoya/boyaというのが作成され、その配下に 3項目とも追加されました。:v_tone2:
![DBに追加されました.png](https://qiita-image-store.s3.amazonaws.com/0/237418/099e7de5-936a-8dbc-8f61-d05f9da5f00a.png)

データを追加する書き方は複数あるみたいなのですが、ワタシが使いそうだなと思ったのはこの2つ
１つ目は上でも書いたパスの後にpushと書くやり方。実はコレ関数が呼ばれる度にデータがジャンジャン追加されます。この英語と数字の羅列は何かと言いますと、キーです。pushすると新しくこのキーが作成されて、その下にuser_sayやらparam_valueやらがデータとして保持されます。

~~~javascript:pushだとデータがジャンジャン追加されます。
admin.database().ref(hoyapath).push({
    user_say:dialogflow_user_say, param_value:dialogflow_param , timestamp: time 
}) 
~~~

こんな感じで呼べば呼ぶほどキーが増えていきます。
![ジャンジャン追加されます.png](https://qiita-image-store.s3.amazonaws.com/0/237418/152322f1-3d54-e8f6-56dd-679448743049.png)

~~~javascript:setだとデータが上書きされます。
admin.database().ref(hoyapath).set({
    user_say:dialogflow_user_say, param_value:dialogflow_param , timestamp: time 
}) 
~~~
setだとキーは作成されずにデータが上書きされています。
![setだと上書きされる.png](https://qiita-image-store.s3.amazonaws.com/0/237418/fe37904a-c4f1-b4fe-21e2-81b08a642d49.png)



今までワタシはDBというとSQLというイメージでデータに触れてきていたので、
FirebaseRealtimeDatabaseのNoSQLという考え方がイマイチしっくりこなかったのですが、
自分でデータを追加したり参照してみたりするうちに何となく理解できたように思います。

さて、ここまででFirebaseのDatabaseにデータを追加することが出来ました。
今回も最後まで読んで頂き有難うございました。

---
　　　　**次の記事：[❹Databaseへのデータ追加をトリガーに特定のページへ遷移させる](https://qiita.com/tedkuma/items/f35d3c7cd02778c800b6)**

　　　　**前の記事：[❶Dialogflowで簡単なチャットボットを作成](https://qiita.com/tedkuma/items/d892ec31c3cdaf35753b)**
　　　　　　　　　**[❷FirebaseのFunctionsでボットに返事をさせる(Dialogflow V2 API)](https://qiita.com/tedkuma/items/9ceb17936c714a205a74)**