【MongoDB】APIログ取るのに手軽で最高だった件 (+intellijだとさらに手軽)

#はじめに

気にはなっていたけど、なかなか触れる機会が無かった。。
そんな、同じクラスのあの子のような存在、それがmongoDBでした。
実際、使ってみると手軽でとても使いやすい。

こちらの記事では、簡単にインストールから導入までをまとめてみました。


#MongoDBを使った開発内容
趣味の個人開発でMongoDBを利用しました。
[APIを利用したbitcoin自動売買システム]

- bitcoin値取得にCryptWatchAPIを使用
- bitcoin売買にBitflyerAPIを使用
- 開発言語:Node.js
- 開発環境:macOS Catalina
- デプロイ環境: AWS:EC2:ubuntu18.04LTS

MongoDBはbitcoin売買時の値段と、その売買判断に使われた値のログを取りたくて使用しました。



#mongoDBとは
誤解を恐れずに極端に言うと、

**データをJSON形式でレコードできるデータベースです**

すいません! ここでは、わかりやすさ優先しましたm(_ _)m
(玄人の方々、マサカリ投げないでください。)

他にも、
スケーラビリティ(拡張)しやすい、
スキーマレス(事前定義不要)である。 などなど、、ありますが、
詳しく知りたい方は以下のページをおすすめします。
[詳しいオススメページ1](https://utage.headwaters.co.jp/blog/archives/5051)
[詳しいオススメページ2](https://qiita.com/Brutus/items/8a67a4db0fdc5a33d549)


#APIをレコードするのに最適!
mongoの特徴

- スキーマレスで、
- JSON形式

これが、APIを記録するのにすごく相性がいいです。
つまり、
**APIからレスポンスされたJSONをそのままインサートすることができる!**
さらに、
**毎回APIの構造が変わってもそのままインサート可能!!**
すごい楽ですね、
スキーマレスなので難しく考えず、ひとまず突っ込んで置くことができます。

これが、RDBMSだとどうなるか?

- スキーマを細かく定義した上で、例外処理を施し構造が変わるものは省いてインサートする。  
- string,textとしてまるごとインサート

どちらも大変です。。
受け取る可能性のあるJSON内容を想定して、スキーマを細かく定義した上で、
処理は、レスポンスされたJSONをカラムに収まるように全部分解したり、例外処理を書いたり。。
2つ目は、まる投げでインサートすればいいのですが、columnがTEXT形式でも文字数制限あります。
mysqlだと最大長が65,535(216 − 1)文字になります。データを利用するときはまた、JSON形式に戻して。。
うぅ、吐きそうです(；´Д｀)
しかも、ノード同士の構造を捨てちゃってます。

*「今は何に使うかわかんないけどー、
あとで、面白いことに使いたいから、とりあえずサクッとデータ残しておこう♪」*
こんなノリには、ぜひMongoDBです。

私のbitcoin売買システムも、
将来、趣味で分析したり、機械学習で回せたらオモロイだろうなーってノリだけです。
使えそうな値と、APIをまるごと、とりあえずインサートおく。
APIの構造が多少変わっても気にしない。

まずはその手軽さを触ってみることをオススメします。
それでは、簡単に導入方法をまとめます。


#インストール
##macOS
brewを使って、簡単にインストールできます。

```shell

brew install mongodb

#自動起動に設定
brew services start mongodb

```

##ubuntu18.04LTS
ubuntuはやや面倒です。
aptの管理ライブラリが最新のMongDBとなっていないため、
Mongoの公式から、パッケージを展開してインストールする必要があります。

```shell

#パッケージ管理システムに公開鍵を登録
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4

#ダウンロード用のリストファイルを作成
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list

#パッケージ管理システムのデータベースをリロード
sudo apt-get update

#最新の安定版をインストール
sudo apt-get install -y mongodb-org

#MongoDBを自動起動にする
sudo systemctl enable mongod

#MongoDBを起動
sudo service mongod start
```


##raspbrerryPi
ラズパイにMongDBの最新バージョンはインストールできません。

正しくは、
ラズパイの公式OS:RasbianOSには、MongDB version2.4.14以上はインストールできません。

上記のMongoDBバージョンが、64bit対応のみとなっていますが、
RasbianOSが、32bitとなっているためです。

実は、ラズパイ自体は64bitのため
OSに引きづられて最新のMongoDBが利用できなくなっています。
ですので、OSを入れ替えたら使用できるかもしれません。
[詳しくはこちら](https://ameblo.jp/mongol-sky/entry-12413849956.html)

mongo2.4以下だと、npmのmongoライブラリも対応していないため、
ラズパイでmongoDBを扱うのは特別な理由が無い限りあまりおすすめしないです。



#実装
##データベースの設定
ターミナルからmongoにデータベースを作成して、利用できるようにします。

```sh
# MongoDBに入る
mongo

# データベース切り替え、作成
use db_name

#データベースの確認
show dbs

#使用しているデータベースを確認
db

#コレクションの作成
db.createCollection("collect_name")

#コレクションを確認
show collections

#コレクションにドキュメントをインサート
db.collect_name.insertOne({ name: "hoge", age: 88})

#コレクション内のドキュメントを確認
db.collect_name.find()

# MongoDBから抜ける
exit
```
ちょっと説明

- use db_name: データベースは無ければ、自動で作成されます。
- collection: mongoではtableでは無く、collectionと言います。
- document:mongoでは1つ1つのデータ(record)のことをdocumentと言います。


##コード実装
Node.jsで実装しました。
以下はベースの実装例です。


```js

const MongoClient = require('mongodb').MongoClient;
const options = {
  useUnifiedTopology : true,
  useNewUrlParser : true
};
const url = 'mongodb://localhost:27017';
const dbName = 'db_name';

//即時関数と、asyncを定義
(async function () {
  let client;

  try {
    client = await MongoClient.connect(
        url,
        options,
    );
    //DB取得
    const db = client.db(dbName);

    //DBを操作
    await insertDoc(db);
    await findDoc(db);
  } catch (err) {
    //接続失敗
    console.log(err);
  }

  //接続を切る
  client.close();
})();

//Insert
function insertDoc(db) {
  const collection = db.collection('collect_name');
  collection.insertMany(
      [{ name: 'hoge', age: 88 }, { name: 'fuga', age: 14 }],
      (err, result) => {
        console.log('Success inserted');
      },
  );
}

//Find
function findDoc(db) {
  const collection = db.collection('collect_name');
  collection.find({}).toArray((err, docs) => {
        //検索内容をコンソール出力
        console.log(docs);
      });
}

```




#データ確認
bitcoinの売買データをmongoで取得してみました。

##標準のデータ確認

```sh
#terminalからの標準のデータ確認
{ 
"_id" : ObjectId("5df9c2ba73160d276ad2e3ad"), 
"flag" : "buy", 
"label" : "買い注文", 
"created_at" : ISODate("2019-12-18T06:10:02.072Z"), 
"strTime" : "2019/12/18 15:10:02", 
"price" : 737491, 
"shortMA" : 737293.825779211, 
"longMA" : 736227.9333333333, 
"countHigh" : 4, 
"records" : [ 735413, 735522, 735314, 735516, 735691, 735913, 736276, 736316, 736366, 736788, 736586, 736472, 735565, 735245, 735327, 735259, 735677, 735745, 736058, 736238, 736448, 736713, 736388, 736426, 736954, 737198, 736975, 737479, 737479, 737491 ] 
}
```

一部説明します

- _id: mongoから自動で振られるid
- created_at: ISODATE形式、datetime形式でinsertすることができます。
- shortMA: 過去5回分のpriceの移動平均金額を算出
- longMA: 過去30回分のpriceの移動平均金額を算出
- records: 過去のpriceリスト。リスト形式でそのままinsertしています。

データの形式がlistでも、さらにツリーが入れ子状態になっても、insertすることができます。

##Intellij(jetBrains)を利用
CLIからだと、RDBMSよりも一覧性なくて見ずらいですね。データの閲覧はIDEや、ソフトをオススメします。
私は、IntelliJを使っています。
一度だけ接続設定をすれば、それ以後、ダブルクリックだけで、DBに接続してこのようにデータ閲覧できます。
ターミナルでコマンドを打つよりも、データ確認が手軽で早くて、見やすいです。

本来は上記のようなJSON形式のnodeツリーが、テーブル表示で一覧できます。
![スクリーンショット 2020-02-12 13.54.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215645/dea832b7-04f0-8345-287b-80d6a1185f7f.png)
クリックひとつでソートもできますし、絞り込みも簡単です。
ツリー形式での閲覧もできます。
![スクリーンショット 2020-02-12 14.06.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215645/c6cb99dd-e2ec-5d6f-8c58-4059f47bdb2c.png)

transposed table 日本語で何形式と言うのでしょう?こんな閲覧方法もできます。
![スクリーンショット 2020-02-12 14.06.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215645/ef6cd44d-327d-3929-3415-d2fb79811523.png)

強いて不満を言えば、
table viewのとき、列の順番がバラバラとなるのが気になります。
(そもそもMongoDBにはDDLで読み取れるようなculumnの順番という概念がないのでしょうが無いです。)



#おわりに
MongDBは、お手軽で使い勝手がよいDBです。
APIデータを、今の時点ではどんな風に活用するか厳密に決めていないけど、
ひとまず導入しておいて後で考えるには、MongoDBは良い選択肢だと思います♪

最後までお読みいただきありがとうございました。