チュートリアル: JavaScript SDK を使用して Node.js Web アプリを構築して Azure Cosmos DB の NoSQL 用 API アカウントを管理する

適用対象: NoSQL

お客様は開発者として、NoSQL ドキュメント データが使用されるアプリケーションをお持ちかもしれません。 Azure Cosmos DB の NoSQL 用 API アカウントを使用して、このドキュメント データを格納し、それにアクセスできます。 この Node.js チュートリアルでは、Azure Cosmos DB の NoSQL 用 API アカウントからデータを格納およびアクセスする方法について説明します。 このチュートリアルでは、Microsoft Azure App Service のWeb Apps 機能にホストされた Node.js Express アプリケーションを使用します。 このチュートリアルでは、タスクの作成、取得、および完了を行える Web ベースのアプリケーション (Todo アプリ) を構築します。 タスクは、JSON ドキュメントとして Azure Cosmos DB に保存するものとします。

このチュートリアルでは、Azure portal を使用して Azure Cosmos DB の NoSQL 用 API アカウントを作成する方法を示します。 クレジット カードまたは Azure サブスクリプションがない場合は、次のことが行えます。

  • 無料の Azure Cosmos DB 試用版アカウントを設定する。
  • Node.js SDK に基づく Web アプリを構築および実行して、データベースとコンテナーを作成する。
  • コンテナーに項目を追加する。

このチュートリアルでは、JavaScript SDK バージョン 3.0 を使用し、次のタスクについて説明します。

  • Azure Cosmos DB アカウントを作成する
  • 新しい Node.js アプリケーションを作成する
  • アプリケーションを Azure Cosmos DB に接続する
  • アプリケーションを実行し、Azure にデプロイする

前提条件

この記事の手順を実行する前に、以下のリソースがあることを確認してください。

Azure Cosmos DB アカウントを作成する

まず最初に、Azure Cosmos DB アカウントを作成します。 アカウントが既にある場合や、このチュートリアルに Azure Cosmos DB Emulator を使用する場合は、「新しい Node.js アプリケーションを作成する」に進むことができます。

  1. Azure portal のメニューまたは [ホーム] ページで、 [リソースの作成] を選択します。

  2. Azure Cosmos DB を検索します。 [作成]>[Azure Cosmos DB] を選択します。

  3. [Azure Cosmos DB アカウントの作成] ページで、 Azure Cosmos DB for NoSQL セクション内の [作成] オプションを選択します。

    Azure Cosmos DB には、いくつかの API が用意されています:

    • NoSQL (ドキュメント データ用)
    • PostgreSQL
    • MongoDB (ドキュメント データ用)
    • Apache Cassandra
    • テーブル
    • Apache Gremlin (グラフ データ用)

    NoSQL 用 API の詳細については、「Azure Cosmos DB へようこそ」を参照してください。

  4. [Azure Cosmos DB アカウントの作成] ページで、新しい Azure Cosmos DB アカウントの基本的な設定を入力します。

    設定 説明
    サブスクリプション サブスクリプション名 この Azure Cosmos DB アカウントに使用する Azure サブスクリプションを選択します。
    リソース グループ リソース グループ名 リソース グループを選択するか、 [新規作成] を選択し、新しいリソース グループの一意の名前を入力します。
    アカウント名 一意の名前 自分の Azure Cosmos DB アカウントを識別するための名前を入力します。 指定した名前に documents.azure.com が付加されて URI が作成されるので、一意の名前を使用してください。 名前に含めることができるのは、英小文字、数字、ハイフン (-) のみです。 3 から 44 文字にする必要があります。
    場所 ユーザーに最も近いリージョン Azure Cosmos DB アカウントをホストする地理的な場所を選択します。 データに最も高速にアクセスできるよう、お客様のユーザーに最も近い場所を使用します。
    容量モード プロビジョニング スループットまたはサーバーレス プロビジョニング スループット モードでアカウントを作成するには、 [Provisioned throughput](プロビジョニング スループット) を選択します。 サーバーレス モードでアカウントを作成するには、 [サーバーレス] を選択します。
    Apply Azure Cosmos DB free tier discount (Azure Cosmos DB Free レベル割引を適用する) [適用] または [適用しない] Azure Cosmos DB Free レベルのアカウントでは、最初の 1000 RU/s と 25 GB のストレージを無料でご利用いただけます。 Free レベルの詳細を確認してください。
    合計アカウント スループットを制限する 選択済みかどうか このアカウントでプロビジョニングできるスループットの総量を制限する。 この制限により、プロビジョニングされたスループットに関連する予期しない料金が回避されます。 この制限は、アカウントの作成後に更新または削除できます。

    Azure サブスクリプションにつき所有できる Free サービス レベルの Azure Cosmos DB アカウントは 1 つまでです。また、アカウントの作成時にオプトインする必要があります。 Free レベル割引を適用するオプションが表示されない場合は、サブスクリプション内の別のアカウントが Free レベルで既に有効になっています。

    [Azure Cosmos DB アカウントの作成] ページを示すスクリーンショット。

    Note

    [Capacity mode](容量モード) として [サーバーレス] を選択した場合、以下のオプションは利用できません。

    • Apply Free Tier Discount (Free レベルの割引の適用)
    • 合計アカウント スループットを制限する
  5. [グローバル分散] タブで、次の詳細を構成します。 このクイックスタートでは、既定値のままにしておいてかまいません。

    設定 説明
    geo 冗長性 無効化 リージョンをペア リージョンとペアリングすることによる、アカウントでのグローバル配信を有効または無効にします。 アカウントには、後でさらにリージョンを追加できます。
    マルチリージョン書き込み 無効化 マルチリージョン書き込み機能を使用すると、世界中のデータベースとコンテナーで、プロビジョニングされたスループットを利用できます。
    可用性ゾーン 無効にする Availability Zones は、アプリケーションの可用性と回復性をさらに向上させるのに役立ちます。

    注意

    前の [基本] ページで [容量モード] として [サーバーレス] を選択した場合、次のオプションは使用できません:

    • geo 冗長
    • マルチリージョン ライター
  6. 必要に応じて、次のタブでさらに詳細を構成できます:

    • ネットワーク仮想ネットワークからのアクセスを構成します。
    • Backup Policy定期的または継続的のいずれかのバックアップ ポリシーを構成します。
    • 暗号化。 サービス マネージド キーまたはカスタマー マネージド キーのいずれかを使用します。
    • タグ。 タグは名前と値のペアで、同じタグを複数のリソースやリソース グループに適用することでリソースを分類したり、統合した請求を表示したりできるようにします。
  7. [Review + create](レビュー + 作成) を選択します。

  8. アカウントの設定を確認し、 [作成] を選択します。 アカウントの作成には数分かかります。 ポータル ページに "デプロイが完了しました" と表示されるまで待ちます。

    デプロイが完了したことを示すスクリーンショット。

  9. [リソースに移動] を選択し、Azure Cosmos DB アカウント ページに移動します。

    Azure Cosmos DB アカウント ページを示すスクリーンショット。

Azure Cosmos DB アカウント ページに移動し、[キー] を選択します。 次に作成する Web アプリケーションで使用する値をコピーします。

[Azure Cosmos DB アカウント] ページで [キー] ボタンが強調表示されている Azure portal のスクリーンショット

新しい Node.js アプリケーションを作成する

次に、Express フレームワークを使用した基本的な Hello World Node.js プロジェクトの作成方法を学習します。

  1. Node.js のコマンド プロンプトなどのお好きなターミナルを開きます。

  2. 新しいアプリケーションを保存するディレクトリに移動します。

  3. Express ジェネレーターを使用し、 todoという名前の新しいアプリケーションを作成します。

    express todo
    
  4. todo ディレクトリを開き、依存関係をインストールします。

    cd todo
    npm install
    
  5. 新しいアプリケーションを実行します。

    npm start
    
  6. ブラウザーで新しいアプリケーションを表示するには、http://localhost:3000 にアクセスします。

    ブラウザー ウィンドウでの Hello World アプリケーションのスクリーンショット。

    ターミナル ウィンドウで Ctrl キーを押しながら C キーを押してアプリケーションを停止し、 [y] を選択してバッチ ジョブを終了します。

必要なモジュールのインストール

package.json ファイルは、プロジェクトのルートに作成されるファイルの 1 つです。 このファイルには、Node.js アプリケーションで必要な他のモジュールのリストが含まれています。 このファイルは、このアプリケーションを Azure にデプロイするときに、アプリケーションをサポートするために Azure にインストールする必要があるモジュールを判断するために使用されます。 このチュートリアルのために、さらに 2 つのパッケージをインストールします。

  1. npm を使用して @azure/cosmos モジュールをインストールします。

    npm install @azure/cosmos
    

Node.js アプリケーションを Azure Cosmos DB に接続する

初期セットアップと構成が完了したら、Todo アプリケーションが Azure Cosmos DB と通信するために必要なコードを記述する方法を学習します。

モデルを作成する

  1. お客様のプロジェクト ディレクトリのルートに、models という名前の新しいディレクトリを作成します。

  2. models ディレクトリ内に、taskDao.js という名前の新しいファイルを作成します。 このファイルには、データベースとコンテナーの作成に必要なコードを含めます。 また、Azure Cosmos DB 内のタスクの読み取り、更新、作成、および検索を行うメソッドも定義します。

  3. 次のコードを taskDao.js ファイルにコピーします。

     // @ts-check
     const CosmosClient = require('@azure/cosmos').CosmosClient
     const debug = require('debug')('todo:taskDao')
    
     // For simplicity we'll set a constant partition key
     const partitionKey = undefined
     class TaskDao {
       /**
        * Manages reading, adding, and updating Tasks in Azure Cosmos DB
        * @param {CosmosClient} cosmosClient
        * @param {string} databaseId
        * @param {string} containerId
        */
       constructor(cosmosClient, databaseId, containerId) {
         this.client = cosmosClient
         this.databaseId = databaseId
         this.collectionId = containerId
    
         this.database = null
         this.container = null
       }
    
       async init() {
         debug('Setting up the database...')
         const dbResponse = await this.client.databases.createIfNotExists({
           id: this.databaseId
         })
         this.database = dbResponse.database
         debug('Setting up the database...done!')
         debug('Setting up the container...')
         const coResponse = await this.database.containers.createIfNotExists({
           id: this.collectionId
         })
         this.container = coResponse.container
         debug('Setting up the container...done!')
       }
    
       async find(querySpec) {
         debug('Querying for items from the database')
         if (!this.container) {
           throw new Error('Collection is not initialized.')
         }
         const { resources } = await this.container.items.query(querySpec).fetchAll()
         return resources
       }
    
       async addItem(item) {
         debug('Adding an item to the database')
         item.date = Date.now()
         item.completed = false
         const { resource: doc } = await this.container.items.create(item)
         return doc
       }
    
       async updateItem(itemId) {
         debug('Update an item in the database')
         const doc = await this.getItem(itemId)
         doc.completed = true
    
         const { resource: replaced } = await this.container
           .item(itemId, partitionKey)
           .replace(doc)
         return replaced
       }
    
       async getItem(itemId) {
         debug('Getting an item from the database')
         const { resource } = await this.container.item(itemId, partitionKey).read()
         return resource
       }
     }
    
     module.exports = TaskDao
    
  4. taskDao.js ファイルを保存して閉じます。

コントローラーの作成

  1. プロジェクトの routes ディレクトリ内に、tasklist.js という名前の新しいファイルを作成します。

  2. 次のコードを tasklist.js に追加します。 このコードによって、tasklist.js で使用される CosmosClient および async モジュールが読み込まれます。 また、TaskList クラスが定義されます。先ほど定義した TaskDao オブジェクトのインスタンスとして、このクラスが渡されます。

     const TaskDao = require("../models/TaskDao");
    
     class TaskList {
       /**
        * Handles the various APIs for displaying and managing tasks
        * @param {TaskDao} taskDao
        */
       constructor(taskDao) {
         this.taskDao = taskDao;
       }
       async showTasks(req, res) {
         const querySpec = {
           query: "SELECT * FROM root r WHERE r.completed=@completed",
           parameters: [
             {
               name: "@completed",
               value: false
             }
           ]
         };
    
         const items = await this.taskDao.find(querySpec);
         res.render("index", {
           title: "My ToDo List ",
           tasks: items
         });
       }
    
       async addTask(req, res) {
         const item = req.body;
    
         await this.taskDao.addItem(item);
         res.redirect("/");
       }
    
       async completeTask(req, res) {
         const completedTasks = Object.keys(req.body);
         const tasks = [];
    
         completedTasks.forEach(task => {
           tasks.push(this.taskDao.updateItem(task));
         });
    
         await Promise.all(tasks);
    
         res.redirect("/");
       }
     }
    
     module.exports = TaskList;
    
  3. tasklist.js ファイルを保存して閉じます。

config.js の追加

  1. プロジェクト ディレクトリのルートに、config.js という名前の新しいファイルを作成します。

  2. 次のコードを config.js ファイルに追加します。 このコードにより、アプリケーションに必要な値と構成設定が定義されます。

    const config = {};
    
    config.host = process.env.HOST || "[the endpoint URI of your Azure Cosmos DB account]";
    config.authKey =
      process.env.AUTH_KEY || "[the PRIMARY KEY value of your Azure Cosmos DB account";
    config.databaseId = "ToDoList";
    config.containerId = "Items";
    
    if (config.host.includes("https://localhost:")) {
      console.log("Local environment detected");
      console.log("WARNING: Disabled checking of self-signed certs. Do not have this code in production.");
      process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
      console.log(`Go to http://localhost:${process.env.PORT || '3000'} to try the sample.`);
    }
    
    module.exports = config;
    
  3. Azure portal にあるお客様の Azure Cosmos DB アカウントの [キー] ページで見つかる値を使用して、config.js ファイルの HOST および AUTH_KEY の値を更新します。

  4. config.js ファイルを保存して閉じます。

app.js の変更

  1. プロジェクト ディレクトリ内の app.js ファイルを開きます。 これは、先ほどの Express Web アプリケーション作成時に作成されたファイルです。

  2. 次のコードを app.js ファイルに追加します。 このコードにより、使用される構成ファイルが定義され、以降のセクションで使用するいくつかの変数に値が読み込まれます。

     const CosmosClient = require('@azure/cosmos').CosmosClient
     const config = require('./config')
     const TaskList = require('./routes/tasklist')
     const TaskDao = require('./models/taskDao')
    
     const express = require('express')
     const path = require('path')
     const logger = require('morgan')
     const cookieParser = require('cookie-parser')
     const bodyParser = require('body-parser')
    
     const app = express()
    
     // view engine setup
     app.set('views', path.join(__dirname, 'views'))
     app.set('view engine', 'jade')
    
     // uncomment after placing your favicon in /public
     //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
     app.use(logger('dev'))
     app.use(bodyParser.json())
     app.use(bodyParser.urlencoded({ extended: false }))
     app.use(cookieParser())
     app.use(express.static(path.join(__dirname, 'public')))
    
     //Todo App:
     const cosmosClient = new CosmosClient({
       endpoint: config.host,
       key: config.authKey
     })
     const taskDao = new TaskDao(cosmosClient, config.databaseId, config.containerId)
     const taskList = new TaskList(taskDao)
     taskDao
       .init(err => {
         console.error(err)
       })
       .catch(err => {
         console.error(err)
         console.error(
           'Shutting down because there was an error settinig up the database.'
         )
         process.exit(1)
       })
    
     app.get('/', (req, res, next) => taskList.showTasks(req, res).catch(next))
     app.post('/addtask', (req, res, next) => taskList.addTask(req, res).catch(next))
     app.post('/completetask', (req, res, next) =>
       taskList.completeTask(req, res).catch(next)
     )
     app.set('view engine', 'jade')
    
     // catch 404 and forward to error handler
     app.use(function(req, res, next) {
       const err = new Error('Not Found')
       err.status = 404
       next(err)
     })
    
     // error handler
     app.use(function(err, req, res, next) {
       // set locals, only providing error in development
       res.locals.message = err.message
       res.locals.error = req.app.get('env') === 'development' ? err : {}
    
       // render the error page
       res.status(err.status || 500)
       res.render('error')
     })
    
     module.exports = app
    
  3. 最後に、app.js ファイルを保存して閉じます。

ユーザー インターフェイスを構築する

次に、ユーザーがアプリケーションと対話できるように、ユーザー インターフェイスを構築します。 前のセクションで作成した Express アプリケーションは、ビュー エンジンとして Jade を使用します。

  1. views ディレクトリ内の layout.jade ファイルは、他の .jade ファイルのグローバル テンプレートとして使われます。 この手順では、Web サイトのデザインに使用されるツールキットである Twitter Bootstrap を使用するために、これを変更します。

  2. views フォルダーにある layout.jade ファイルを開き、その内容を次のコードで置き換えます。

    doctype html
    html
      head
        title= title
        link(rel='stylesheet', href='//ajax.aspnetcdn.com/ajax/bootstrap/3.3.2/css/bootstrap.min.css')
        link(rel='stylesheet', href='/stylesheets/style.css')
      body
        nav.navbar.navbar-inverse.navbar-fixed-top
          div.navbar-header
            a.navbar-brand(href='#') My Tasks
        block content
        script(src='//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.2.min.js')
        script(src='//ajax.aspnetcdn.com/ajax/bootstrap/3.3.2/bootstrap.min.js')
    

    このコードでは、アプリケーション用に一定の HTML をレンダリングするよう Jade エンジンに指示するほか、コンテンツ ページ用のレイアウトを指定できる content という名前の block を作成します。 layout.jade ファイルを保存して閉じます。

  3. アプリケーションで使用されるビューである index.jade ファイルを開きます。 ファイルの内容を次のコードに置き換えます。

    extends layout
    block content
         h1 #{title}
         br
    
         form(action="/completetask", method="post")
          table.table.table-striped.table-bordered
             tr
               td Name
               td Category
               td Date
               td Complete
             if (typeof tasks === "undefined")
               tr
                 td
             else
               each task in tasks
                 tr
                   td #{task.name}
                   td #{task.category}
                   - var date  = new Date(task.date);
                   - var day   = date.getDate();
                   - var month = date.getMonth() + 1;
                   - var year  = date.getFullYear();
                   td #{month + "/" + day + "/" + year}
                   td
                    if(task.completed) 
                     input(type="checkbox", name="#{task.id}", value="#{!task.completed}", checked=task.completed)
                    else
                     input(type="checkbox", name="#{task.id}", value="#{!task.completed}", checked=task.completed)
           button.btn.btn-primary(type="submit") Update tasks
         hr
         form.well(action="/addtask", method="post")
           label Item Name:
           input(name="name", type="textbox")
           label Item Category:
           input(name="category", type="textbox")
           br
           button.btn(type="submit") Add item
    

これはレイアウトを拡張するためのコードであり、layout.jade ファイル内の content プレースホルダーの内容を指定します。 そのレイアウトでは、2 つの HTML フォームを作成しました。

1 つ目のフォームには、データ用のテーブルと、コントローラーの /completeTask メソッドに対する POST によって項目を更新できるボタンが含まれます。

2 番目のフォームには、2 つの入力フィールドと、コントローラーの /addtask メソッドに対する POST によって新しい項目を作成できるボタンが含まれています。アプリケーションを動作させるために必要なものはこれだけです。

アプリケーションをローカルで実行する

アプリケーションをビルドしたら、次の手順を使用して、それをローカルで実行できます。

  1. ローカル コンピューター上でアプリケーションをテストするには、ターミナルで npm start を実行してお客様のアプリケーションを起動し、http://localhost:3000 ページを更新します。 ページは次のスクリーンショットのようになります。

    ブラウザーでの MyTodo List アプリケーションのスクリーンショット。

    ヒント

    layout.jade ファイルまたは index.jade ファイルのインデントについてのエラーが表示される場合は、両ファイルの最初の 2 行がスペースなしで左揃えになっていることを確認してください。 最初の 2 行の前にスペースがある場合は、それらを削除し、両方のファイルを保存してから、ブラウザー ウィンドウを更新します。

  2. [Item Name](項目名) フィールドと [Item Category](項目カテゴリ) フィールドを使用して新しいタスクを入力し、[Add Item](項目の追加) を選択して、それらのプロパティを含むドキュメントを Azure Cosmos DB に作成します。

  3. ページが更新され、ToDo リストに新しく作成された項目が表示されます。

    ToDo リストに新しい項目があるアプリケーションのスクリーンショット。

  4. タスクを完了するには、[Complete](完了) 列のチェック ボックスを選択し、[Update tasks](タスクの更新) を選択して、既に作成したドキュメントを更新し、ビューから削除します。

  5. アプリケーションを停止するには、ターミナル ウィンドウで Ctrl キーを押しながら C キーを押し、[y] を選択してバッジ ジョブを終了します。

アプリケーションを App Service にデプロイする

お使いのアプリケーションがローカルで成功した後、それを Azure App Service にデプロイできます。 ターミナルで、todo アプリ ディレクトリにいることを確認します。 次の az webapp up コマンドを使用して、ローカル フォルダー (todo) 内のコードをデプロイします。

az webapp up --sku F1 --name <app-name>

<app_name> を Azure 全体で一意の名前で置き換えます (有効な文字は、a から z、0 から 9、および - です)。 会社名とアプリ識別子を組み合わせて使用すると、適切なパターンになります。 アプリのデプロイの詳細については、Azure での Node.js アプリのデプロイに関する記事を参照してください。

このコマンドは、完了するまで数分かかることがあります。 このコマンドを使用すると、リソース グループ、App Service プラン、アプリ リソースの作成、ログの構成、ZIP のデプロイの実行に関するメッセージが表示されます。 このコマンドにより、実行中にこれらのメッセージが表示されます。 次に、http://<app-name>.azurewebsites.net でアプリを起動する URL が表示されます。これは、Azure 上のアプリの URL です。

リソースをクリーンアップする

これらのリソースが必要なくなったら、リソース グループ、Azure Cosmos DB アカウント、およびすべての関連リソースを削除できます。 そうするには、Azure Cosmos DB アカウントのためにお客様が使用したリソース グループを選択し、 [削除] を選択した後、削除するリソース グループの名前を確認します。

次のステップ

容量計画のために、既存のデータベース クラスターに関する情報を使用できます。