Node.js + NoSQL(Couchbase) アプリ開発 ステップバイステップガイド (1)

# はじめに

Node.js + NoSQL(Couchbase) を使ったアプリ開発をステップバイステップで解説していきます。本記事は、シリーズの初回として位置付けられます。

## Node.jsコミュニティに向けて

### なぜ、NoSQLデータベースを使うのか

NoSQLの中でも、ここで扱うドキュメント指向データベース（ドキュメントストア）は、データとしてJSONドキュメントを格納します。言わずもがなですが、JSONとは「JavaScript Object Notation」の略で、Node.jsアプリ開発のバックエンドデータベースとしてドキュメントストアを利用することは、MEANスタック(MongoDB、Express、AngularJS、Node.js)にもみられように、自然と言えます。

### なぜ、Couchbaseを使うのか

NoSQL技術同士の比較については、この記事の目的ではないため、多くは触れません。

先にあげたMEANスタックからもわかるように、MongoDBがまずは筆頭に上がる状況を踏まえ、あまり目にする機会のない、日本語によるCouchbaseについての紹介として、興味を持っていただければ幸いです。

一つだけ、Couchbaseに独自の部分として、SQLのJSONドキュメント用の拡張である、Couchbaseのクエリ言語、N1QL(Non 1st-normal-form Query Language: 非第一正規化クエリ言語)の利用について、最後に解説します。

## 前提
- Node.js
    - 開発環境がセットアップされている
- Couchbase Server
    - 開発環境にインストールされている(`localhost`でアクセス可能)
    - 管理者ユーザが作成されている(ID: `Administrator`、パスワード: `password`）
    - Bucket(`test`)が作成されている
    - コマンドラインツールにパスが通っている

## 動作確認環境
- Mac OS Catalina Version 10.15.6
    - コマンドラインツールパス：`/Applications/Couchbase Server.app/Contents/Resources/couchbase-core/bin/`
- Node.js
     - node v15.4.0
     - npm 7.0.15
- Couchbase Server 7.0 BETA

# プロジェクト準備

プロジェクト用のディレクトリを作成し、その中で作業を開始します。

はじめに下記を実行します。

```
$ npm init -y
```
package.jsonファイルが作成されます。

Couchbase SDKをインストールし、package.jsonに追記します。

```
$ npm install couchbase --save
```

package.jsonに以下のような依存関係が追記されます。

```
  "dependencies": {
    "couchbase": "^3.1.0"
  }
```

# プログラム作成

`index.js`ファイルを作成し、以下の内容を追加していきます。

## Couchbaseへの接続


```javascript

const couchbase = require("couchbase");

const cluster = new couchbase.Cluster("couchbase://localhost", {
  username: "Administrator",
  password: "password",
});

```

## バケットへの接続

```javascript

const bucket = cluster.bucket("test");

const collection = bucket.defaultCollection();

```

## サンプルデータ定義

```javascript


const user = {
  type: "user",
  id: 1,
  name: "田中",
};

```

## ドキュメント登録関数定義

```javascript
const upsertDocument = async (doc) => {
  try {
    const key = `${doc.type}_${doc.id}`;
    const result = await collection.upsert(key, doc);
    console.log("Upsert: ");
    console.log(result);
  } catch (error) {
    console.error(error);
  }
};
```
## ドキュメント取得関数定義

```javascript
const getDocumentByKey = async (key) => {
  try {
    const result = await collection.get(key);
    console.log("Get: ");
    console.log(result);
  } catch (error) {
    console.error(error);
  }
};

```
## 処理実行部

```javascript
upsertDocument(user);

getDocumentByKey("user_1");
```

# プログラム実行

```
$ node index.js
```

下記のような結果が出力されます。

```shell
Upsert: 
{
  cas: CbCas { '0': <Buffer 00 00 05 1b f9 1e 51 16> },
  token: CbMutationToken {
    '0': <Buffer d8 18 d7 a9 dd 24 00 00 03 00 00 00 00 00 00 00 2f 00 00 00 00 00 00 00 74 65 73 74 00 00 00 00 28 a2 03 05 01 00 00 00 40 a2 03 05 01 00 00 00 28 a2 ... 230 more bytes>
  }
}
Get: 
{
  cas: CbCas { '0': <Buffer 00 00 05 1b f9 1e 51 16> },
  content: { type: 'user', id: 1, name: '田中' }
}
```

Ctrl+Dでプロセスを抜けてください。

# 実行結果確認

Couchbase Serverのコマンドラインツール(`cbq`)を使って、登録されたデータを確認します。

```
$ cbq -u Administrator
 Enter Password: 
 Connected to : http://localhost:8091/. Type Ctrl-D or \QUIT to exit.

```
クエリ(`SELECT * from test;`)を実行してみます。

以下のようなエラーになりました。

```shell
cbq> SELECT * from test;
{
    "requestID": "00fda8f3-d64e-4d8c-85c1-ad810f921bd2",
    "errors": [
        {
            "code": 4000,
            "msg": "No index available on keyspace test that matches your query. Use CREATE INDEX or CREATE PRIMARY INDEX to create an index, or check that your expected index is online."
        }
    ],
    "status": "fatal",
    "metrics": {
        "elapsedTime": "438.814µs",
        "executionTime": "368.037µs",
        "resultCount": 0,
        "resultSize": 0,
        "serviceLoad": 2,
        "errorCount": 1
    }
}
cbq> 
```

メッセージ（"No index available on keyspace test that matches your query. Use CREATE INDEX or CREATE PRIMARY INDEX to create an index, or check that your expected index is online."）にもある通り、クエリを実行するには、インデックスが作成されている必要があります。

プライマリインデックスを作成します。

```
cbq> CREATE PRIMARY INDEX test_primary ON test;
{
    "requestID": "2c482905-b794-4092-bb0b-8d8cb76bc535",
    "signature": null,
    "results": [
    ],
    "status": "success",
    "metrics": {
        "elapsedTime": "1.872931032s",
        "executionTime": "1.872853887s",
        "resultCount": 0,
        "resultSize": 0,
        "serviceLoad": 2
    }
}
cbq> 
```

先ほどのクエリを再度、実行します。

以下のようにクエリの結果が表示されました。

```
cbq> SELECT * from test;
{
    "requestID": "9b80a8eb-3605-4ff8-84fb-0a435959e4e1",
    "signature": {
        "*": "*"
    },
    "results": [
    {
        "test": {
            "id": 1,
            "name": "田中",
            "type": "user"
        }
    }
    ],
    "status": "success",
    "metrics": {
        "elapsedTime": "78.632291ms",
        "executionTime": "78.571384ms",
        "resultCount": 1,
        "resultSize": 113,
        "serviceLoad": 2
    }
}
```

結果（"results"の値）が幾分冗長なので、以下のようにクエリを微修正して、実行します。

```
cbq> SELECT test.* from test;
{
    "requestID": "14dae1e2-cf81-45ae-8c55-2f64ad975743",
    "signature": {
        "*": "*"
    },
    "results": [
    {
        "id": 1,
        "name": "田中",
        "type": "user"
    }
    ],
    "status": "success",
    "metrics": {
        "elapsedTime": "1.034558ms",
        "executionTime": "969.805µs",
        "resultCount": 1,
        "resultSize": 73,
        "serviceLoad": 2
    }
}
```

# 最後に

今回の記事は以上です。

今回のプログラムでは、キーによるアクセスのみを扱い、クエリでのアクセスについては、コマンドラインツールのみで扱いましたが、クエリをプログラムで実行することも、当然可能です。また、クエリについては、今回紹介したような単純なものではなく、一般にSQLを使った開発で用いられているようなもっと複雑なものが利用可能です。これについては、今後の記事で紹介できればと思っています。

また、Node.jsの本来のあり方を考えると、上記のような一度だけ実行するプログラムを作成・実行することは、直感的ではないかもしれません。サーバ・プログラム化についても、今後の記事で紹介していきたいと考えています。

今回は、非常に単純なプログラムとして作成したことで、データベースへの接続と、データの登録・取得という、本質的な部分のみを見て行くことができたかと思います（Node.js経験者にとっては、それ以外の部分は、よく知られているところかとも思います）。また、MongoDBの経験者が読まれた際に、Couchbaseでの実装について、MongoDBと比べて、どのような違い（と共通点）があるかが分かりやすいものになっていれば幸いです。

最後に、ここで紹介したプログラムを下記に公開していますので、適宜ご参照・ご利用ください。

https://github.com/YoshiyukiKono/couchbase_step-by-step_node_jp