FirebaseとAlgoliaの簡単な検索機能

**今回作ったのはこちらになります**
![gif.gif](https://qiita-image-store.s3.amazonaws.com/0/236873/b944b561-f5e3-0af9-98fe-b1aaaff66839.gif)

 **今回は必要最低限のAlgoliaの使い方を載せています。**
もっと専門的なことをやりたいという方は公式などにもいろいろ載っているので参考にしてください。
Algolia自体が検索に加えて、リサーチなどもしてくれる機能もあり、大手の検索エンジンを持っているところなども使っているということで拡張性もとてもいいです。

# Algoliaとは
検索APIのひとつでFirebase以外にも自前でデータをアップロードすれば簡単に検索機能を実装することができます。


## Algoliaのセットアップ
#### APIキーの確認
まずは[Algoloa](https://www.algolia.com)のアカウントを作ります。
そこでAPIキーを後で使うのでメモっておきましょう。

- Application ID
- Search-OnlyAPI
- Admin API Key(＊この記事では使いません)

![dfgggg.png](https://qiita-image-store.s3.amazonaws.com/0/236873/2aecb17f-059d-675c-9f04-602ac53d36ca.png)


#### インデックスを作成
今回は簡単に「sample」をいうインデックスを作っておきます。
インデックス名も忘れるときがたまにあるのでメモっとくといいです。

![asodkepwo.png](https://qiita-image-store.s3.amazonaws.com/0/236873/ac432bb3-7794-ed44-471f-034c917a2275.png)

## FIrebaseのセットアップ

**こちらも[Firebase](https://console.firebase.google.com/)のアカウントを作ります。**
プロジェクトを作り「ウェブアプリにFirebaseを追加」というところを開くと以下のようなものが出てくると思うのでそれをメモっておきましょう。

```html
<script src="https://www.gstatic.com/firebasejs/4.11.0/firebase.js"></script>
<script>
  // Initialize Firebase
  var config = {
    apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    authDomain: "XXXXXXXXXXXXXX.firebaseapp.com",
    databaseURL: "https://XXXXXXXXXX.firebaseio.com",
    projectId: "XXXXXXXXXX",
    storageBucket: "XXXXXXXX.appspot.com",
    messagingSenderId: "000000000000"
  };
  firebase.initializeApp(config);
</script>
```
#### データベースの初期化
まずはデータベースの種類を選択します。

![gfg.png](https://qiita-image-store.s3.amazonaws.com/0/236873/709a597b-d88f-6624-c91f-1779eee17eec.png)

##### ルールの変更(Firebaseでログインをしている場合はいりません)
データベースはセキュリティの観点から初期状態はfirebaseでログインしていないと使えないようにルールが組まれています。
そのルールを今回は誰でもデータベースを使えるように変更しておきます。

初期ではこのようにルールが設定されています
![gfgfgg.png](https://qiita-image-store.s3.amazonaws.com/0/236873/3d96cb5a-4239-eb0d-7967-7106a5842c6a.png)

それをこのように変更して保存します。

```json
{
  "rules": {
    ".read": "true",
    ".write": "true"
  }
}
```

## FirebaseとAlgoliaを繋げる
[ここ](https://qiita.com/Baisel/items/dfb7b539d95c2183af31)を参考にしてください。


# コーディング
今回はデータを生成してから検索結果を出すまでの一連のページを作っています。

- save.html 　　← データを生成してそれをFirebaseに保存する
- index.html 　 ← Algoloaからデータを検索
- res.html　  　 ← 検索されたデータを表示　

このような構成となっています　

 **今回のソースは[こちら](https://github.com/Baisel/Algolia_sample/tree/master/Search)にあります**

## データ保存(save.html)

```html:save.html 
<!DOCTYPE html>
<html lang="jp">

<head>
    <meta charset="UTF-8">
    <script src="https://www.gstatic.com/firebasejs/4.11.0/firebase.js"></script>
    <script src="./js/save.js"></script>
    <title>Save</title>
</head>

<body>
    <input type="text" id="tx1" placeholder="Nameを入力" required>
    <br />
    <input type="text" id="tx2" placeholder="memoを入力" required>
    <br />
    <button onclick="Create();">保存</button>
</body>
</html>
```

```javascript:save.js
      //以下には自分のに表示されたものを入力する
      var config = {
            apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            authDomain: "XXXXXXXXXXX.firebaseapp.com",
            databaseURL: "https://XXXXXXXXXXX.firebaseio.com",
            projectId: "XXXXXXXXXXX",
            storageBucket: "XXXXXXXXXX.appspot.com",
            messagingSenderId: "0000000000000"
        };
        firebase.initializeApp(config);

        function Create() {
           //入力データを取得
            names = document.getElementById("tx1").value;
            memos = document.getElementById("tx2").value;

            //Firebaseのデータベースにデータを保存する
            firebase.database();
            var commentsRef = firebase.database().ref('msg');
            commentsRef.push({ name: names, memo: memos })
            alert("保存");
        }
```

成功の場合はこのようにFirebaseのデータベースにデータが追加されています。
![fffff.png](https://qiita-image-store.s3.amazonaws.com/0/236873/26b2cb58-5cb7-5a15-af90-4be59f14856e.png)


## 検索(index.html)
Realtime Database(FIrebaseのデータベース)ではデータの整合性を保つために「objectID」が各データに振られます。上の画像の「-L7~」というのがobjectIDです。

これをSQLで言う主キーのように扱い検索されたデータを受け渡します。
データの受け渡しについては今回は簡単にURLにiddとして記述しデータを受け渡します。

```html:index.html
<!DOCTYPE html>
<html lang="jp">

<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.js@2.3/dist/instantsearch.min.css">
    <link rel="stylesheet" type="text/css" href="./css/style.css">
    <title>Search</title>
</head>

<body>
    <header>
        <div>
            <input id="search-input" placeholder="検索">
        </div>
    </header>
    <main>
        <div id="hits"></div>
        <div id="pagination"></div>

        <script type="text/html" id="hit-template">
          <div class="hit">
            <div class="hit-image">
            <!--  <img src="{{image}}" alt="{{name}}">   今回は使わなかったですが画像や動画のURLも保存することができます。-->
            </div>
            <div class="hit-content">
              <h2 class="hit-name"><a href='./res.html?idd={{{objectID}}}'>{{{_highlightResult.name.value}}}</a></h2> <!-- データベースのobjectIDを主キーのように使ってデータを指定しています。-->
              <p class="hit-description">{{{_highlightResult.memo.value}}}</p>
            </div>
          </div>
        </script>
    </main>
    <script src="https://cdn.jsdelivr.net/npm/instantsearch.js@2.3/dist/instantsearch.min.js"></script>
    <script src="./js/app.js"></script>
</body>
</html>
```

```javascript:app.js
var search = instantsearch({
    appId: 'XXXXXXXXXXX',    //メモっていたApplication ID
    apiKey: 'XXXXXXXXXXXXXXXXX', // メモっていたsearch only API key　adminではないです。
    indexName: 'sample',
    urlSync: true,    //ブラウザのURLが同期され、ユーザーは現在の検索状態に対応する貼り付けURLをコピーできます。
    searchParameters: {
        hitsPerPage: 10  //1ページあたりの表示するデータ数
    }
});

//検索範囲を縛ることができます
search.addWidget(
    instantsearch.widgets.searchBox({
        container: '#search-input'
    })
);

// 検索結果を表示する
search.addWidget(
    instantsearch.widgets.hits({
        container: '#hits',
        templates: {
            item: document.getElementById('hit-template').innerHTML,
            empty: "キーワード <em>\"{{query}}\"</em>は存在しません"
        }
    })
);

//ページネーション
search.addWidget(
    instantsearch.widgets.pagination({
        container: '#pagination'
    })
);
//検索をスタートさせる
search.start();
```

**style.cssについては長いので[ここ](https://github.com/Baisel/Algolia_sample/blob/master/Search/css/style.css)にあります。**

## 検索結果表示(res.html)

```html:res.html
<!DOCTYPE html>
<html lang="jp">

<head>
    <meta charset="UTF-8">
 　 <script src="https://www.gstatic.com/firebasejs/4.11.0/firebase.js"></script>
    <script src="./js/res.js"></script>
    <title>Result</title>
</head>

<body>
    <ul>
        <li>ネーム:
            <span id="name"></span>
        </li>
        <li>メモ:
            <span id="memo"></span>
        </li>
    </ul>
</body>

</html>
```

```javascript:res.js
var config = {
    apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    authDomain: "XXXXXXXXXXXXXXX.firebaseapp.com",
    databaseURL: "https://XXXXXXXXXXXX.firebaseio.com",
    projectId: "XXXXXXXXXXX",
    storageBucket: "XXXXXXXXXXXX.appspot.com",
    messagingSenderId: "00000000000000"
};
firebase.initializeApp(config);

function Rodn() {
     //URLから検索されたobjectIDを確認します。
    de = location.search;
    idd = de.split("=");
    var url1 = 'msg/' + idd[1] + '/name'
    var url2 = 'msg/' + idd[1] + '/memo'

   //Firebaseから「name」データを取得してきます
    firebase.database();
    var commentsRef = firebase.database().ref(url1)
    commentsRef.on('value', function (snapshot) {
        names = snapshot.val();
        //「name」データを出力
        document.getElementById('name').textContent = names;

    });
    //Firebaseから「memo」データを取得してきます
    var commentsRef = firebase.database().ref(url2)
    commentsRef.on('value', function (snapshot) {
        memos = snapshot.val();
        //「name」データを出力
        document.getElementById('memo').textContent = memos;

    });

}
Rodn();
```
# まとめ
Firebase、Algoliaともにとても使い勝手のいいプラットフォームなので簡単に検索機能を実装することができます。
Algoliaはクライアントエンドだけでなくバックエンドでの検索等にも使えるので色々試してみたいです。

記事に関する意見やデザインに関する意見が(Markdownをあまり使わないので)あればお願いします~