2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

今更ながらCosmos DBの便利さを試してみた

2
Last updated at Posted at 2026-04-03

手軽に使えるデータベース

まあ今更なんですが、思うところありまして、改めてCosmos DBを試してみました。
これまで、RDB以外のドキュメント系データベースだと、私はIBM Cloudantや、そのベースとなってるApache CouchDBを使うことが多く、Cosmos DBはちゃんと使ったことがありませんでした。
私が今働いているDatadogではCosmos DBをモニタリングすることも可能ですし、ちょっとインテグレーション含めて試してみたくて、今回さわってみるに至りました。

やったことは、
まずローカルにCosmos DBを立てる
ローカルのGUIツールでコンテナやデータの操作を試す
Webのインターフェースを作成し、curlを使ってデータのCRUD処理を試す
AzureにCosmos DBを立てる
クライアントアプリの接続先を変更してローカルと同じ用に操作できるか確認する

せっかく試したので、その手順をログとしてこのブログに残します。

ローカルでCosmos DBを使う

Azure Cosmos DB Emulatorのインストール

Microsoft Artifact Registryにイメージがあるので、これを使ってローカルのDocker環境で起動します。

docker run --detach \
  --publish 8081:8081 \
  --publish 1234:1234 \
  --name cosmosdb-emulator \
  mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview

Localhostにアクセスします。ポートは1234にしたのでその通り指定します。
ここで確認できるURIとプライマリーキーは、後ほどクライアントからの接続に利用します。
Screenshot 2026-04-02 at 16.10.37.png

コンテナー(データベース)とデータの作成

Data Explorerからデータベースを作成します。
Cloudantには無い概念ですがコンテナーというデータベース相当のインスタンスを作成します。
Screenshot 2026-04-02 at 16.11.58.png

ここでは以下のように入力しました。

項目 入力値
Database id myDatabase(Create new)
Container id myContainer
Partition key /id

Screenshot 2026-04-02 at 16.13.22.png

左ペインのHomeの下に「myContainer」が作成されたことが確認できます。
Screenshot 2026-04-02 at 16.13.50.png

Itemsを選択しても、まだ何もデータが入っていないので、データを登録してみます。
Screenshot 2026-04-02 at 16.15.06.png

右ペインに以下の通りのJSONデータを記入し、Saveアイコンをクリックして保存します。
Screenshot 2026-04-02 at 16.15.52.png

{
  "id": "1",
  "name": "Taiji Hagino",
  "city": "Tokyo",
  "role": "Senior Technical Advocate"
}

Itemsにデータが1行追加されました。
Screenshot 2026-04-02 at 16.16.16.png

データを更新してみます。
「role」の項目を書き換えて、Updateアイコン(さっきはSaveアイコンだった)をクリックします。
Screenshot 2026-04-02 at 16.19.37.png

データが更新されました。
Screenshot 2026-04-02 at 16.20.41.png

データを削除します。
Screenshot 2026-04-02 at 16.20.59.png
Screenshot 2026-04-02 at 16.21.10.png
Screenshot 2026-04-02 at 16.21.16.png

データが削除されました。
Screenshot 2026-04-02 at 16.21.28.png
Screenshot 2026-04-02 at 16.23.44.png

これで、Azure Cosmos DBのGUIツールからの操作は問題なくできることを確認しました。
ちなみに、ツールバー部分に「SELECT * FROM c」というのが見えます。この後ろのテキスト入力エリアにWHERE句を指定することで、条件指定したデータを絞り込むことができます。
これは、Cloudant/Couch DBとは異なる部分で、SQLライクな操作ができる機能です。 好みは分かれるでしょうが、RDBに慣れ親しんだワタシ的には嬉しいかもです(笑)

クライアントアプリの作成

CRUDを実行するクライアントアプリ

Node.jsからCosmos DBエミュレーターに接続してCRUDを実装してみます。
index.js を作成します。ここのエミュレーターの接続設定部分で、先ほど出てきたURIとプライマリーキーを記述します。

index.js
const { CosmosClient } = require("@azure/cosmos");

// エミュレーターの接続設定
const endpoint = "http://localhost:8081";
const key = "<Azure Cosmos DB Emulator で発行されたプライマリキー>";

const client = new CosmosClient({ endpoint, key });

async function main() {
  // データベース・コンテナの取得(なければ作成)
  const { database } = await client.databases.createIfNotExists({ id: "myDatabase" });
  const { container } = await database.containers.createIfNotExists({ id: "myContainer" });

  // CREATE
  console.log("--- CREATE ---");
  const { resource: created } = await container.items.create({
    id: "2",
    name: "John Doe",
    city: "New York",
    role: "Developer"
  });
  console.log("作成:", created);

  // READ
  console.log("\n--- READ ---");
  const { resource: item } = await container.item("2", "2").read();
  console.log("取得:", item);

  // UPDATE
  console.log("\n--- UPDATE ---");
  item.role = "Senior Developer";
  const { resource: updated } = await container.items.upsert(item);
  console.log("更新後:", updated);

  // DELETE
  console.log("\n--- DELETE ---");
  await container.item("2", "2").delete();
  console.log("削除完了");

  // 全件取得
  console.log("\n--- 全件取得 ---");
  const { resources: allItems } = await container.items.readAll().fetchAll();
  console.log("全データ:", allItems);
}

main().catch(console.error);

作成したindex.jsを実行します。
Screenshot 2026-04-02 at 16.30.51.png
Screenshot 2026-04-02 at 16.31.17.png

Node.jsで実装した、データの登録、検索、更新、削除がそれぞれ実行され、その結果がターミナルに出力されたことを確認しました。 最後の「全データ:[]」は、DELETE実行後なので取得結果が0件であることを出力しています。

SQLクエリーを試すクライアントアプリ

今度は、SQLクエリーを実行するアプリを実装します。
index2.js を作成します。

index2.js
const { CosmosClient } = require("@azure/cosmos");

const endpoint = "http://localhost:8081";
const key = "<Azure Cosmos DB Emulator で発行されたプライマリキー>";

const client = new CosmosClient({ endpoint, key });

async function main() {
  const { database } = await client.databases.createIfNotExists({ id: "myDatabase" });
  const { container } = await database.containers.createIfNotExists({ id: "myContainer" });

  // テストデータを複数登録
  console.log("--- テストデータ登録 ---");
  const users = [
    { id: "1", name: "Taiji Hagino",  city: "Tokyo",    role: "MVP",               age: 40 },
    { id: "2", name: "John Doe",      city: "New York",  role: "Developer",         age: 30 },
    { id: "3", name: "Jane Smith",    city: "Tokyo",    role: "Designer",          age: 25 },
    { id: "4", name: "Bob Johnson",   city: "London",   role: "Senior Developer",  age: 35 },
    { id: "5", name: "Alice Brown",   city: "Tokyo",    role: "Developer",         age: 28 },
  ];
  for (const user of users) {
    await container.items.upsert(user);
  }
  console.log("5件登録完了\n");

  // クエリ1:全件取得
  console.log("--- クエリ1:全件取得 ---");
  const { resources: all } = await container.items
    .query("SELECT * FROM c")
    .fetchAll();
  console.log(all.map(u => `${u.id}: ${u.name} (${u.city})`));

  // クエリ2:WHERE で絞り込み
  console.log("\n--- クエリ2:Tokyo在住のみ ---");
  const { resources: tokyo } = await container.items
    .query("SELECT * FROM c WHERE c.city = 'Tokyo'")
    .fetchAll();
  console.log(tokyo.map(u => `${u.name} - ${u.role}`));

  // クエリ3:ORDER BY
  console.log("\n--- クエリ3:年齢順(昇順)---");
  const { resources: byAge } = await container.items
    .query("SELECT c.name, c.age FROM c ORDER BY c.age ASC")
    .fetchAll();
  console.log(byAge.map(u => `${u.name}: ${u.age}歳`));

  // クエリ4:パラメータ付きクエリ
  console.log("\n--- クエリ4:Developerのみ(パラメータ使用)---");
  const { resources: devs } = await container.items
    .query({
      query: "SELECT * FROM c WHERE c.role = @role",
      parameters: [{ name: "@role", value: "Developer" }]
    })
    .fetchAll();
  console.log(devs.map(u => `${u.name} (${u.city})`));

  // クエリ5:COUNT
  console.log("\n--- クエリ5:Tokyo在住の人数 ---");
  const { resources: count } = await container.items
    .query("SELECT VALUE COUNT(1) FROM c WHERE c.city = 'Tokyo'")
    .fetchAll();
  console.log(`Tokyo在住: ${count[0]}人`);
}

main().catch(console.error);

コードの中に書いたSQL文が実行され、それぞれの結果がターミナルに出力されました。
Screenshot 2026-04-02 at 16.33.41.png
Screenshot 2026-04-02 at 16.33.52.png

Web APIの実装

Expressを使ってデータベースへ接続するWebサービスを作成します。
全件取得、条件指定取得、IDで1件だけ取得、IDをキーに更新、IDをキーに削除、といった感じ。
app.js を作成します。

app.js
const express = require("express");
const { CosmosClient } = require("@azure/cosmos");

const app = express();
app.use(express.json());

// Cosmos DB 接続設定
const client = new CosmosClient({
  endpoint: "http://localhost:8081",
  key: "<Azure Cosmos DB Emulator で発行されたプライマリキー>"
});
const container = client.database("myDatabase").container("myContainer");

// GET /users - 全件取得
app.get("/users", async (req, res) => {
  const { resources } = await container.items.readAll().fetchAll();
  res.json(resources);
});

// GET /users/search?city=Tokyo&role=Developer など - 条件指定検索
app.get("/users/search", async (req, res) => {
  const { city, role, minAge, maxAge } = req.query;

  let query = "SELECT * FROM c WHERE 1=1";
  const parameters = [];

  if (city) {
    query += " AND c.city = @city";
    parameters.push({ name: "@city", value: city });
  }
  if (role) {
    query += " AND c.role = @role";
    parameters.push({ name: "@role", value: role });
  }
  if (minAge) {
    query += " AND c.age >= @minAge";
    parameters.push({ name: "@minAge", value: parseInt(minAge) });
  }
  if (maxAge) {
    query += " AND c.age <= @maxAge";
    parameters.push({ name: "@maxAge", value: parseInt(maxAge) });
  }

  const { resources } = await container.items
    .query({ query, parameters })
    .fetchAll();
  res.json(resources);
});

// GET /users/:id - 1件取得
app.get("/users/:id", async (req, res) => {
  try {
    const { resource } = await container.item(req.params.id, req.params.id).read();
    res.json(resource);
  } catch {
    res.status(404).json({ error: "ユーザーが見つかりません" });
  }
});

// POST /users - 新規作成
app.post("/users", async (req, res) => {
  const { resource } = await container.items.create(req.body);
  res.status(201).json(resource);
});

// PUT /users/:id - 更新
app.put("/users/:id", async (req, res) => {
  const item = { ...req.body, id: req.params.id };
  const { resource } = await container.items.upsert(item);
  res.json(resource);
});

// DELETE /users/:id - 削除
app.delete("/users/:id", async (req, res) => {
  await container.item(req.params.id, req.params.id).delete();
  res.json({ message: "削除完了" });
});

// サーバー起動
app.listen(3000, () => {
  console.log("サーバー起動: http://localhost:3000");
});

app.js を実行してサーバーを起動します。
Screenshot 2026-04-02 at 17.17.16.png

実際にcurlで確認してみるとこんな感じに出力されました。 エンドポイントの最後に「?city=Tokyo」とか指定すると、条件に合致するデータが表示されます。

Screenshot 2026-04-03 at 18.16.14.png

データ追加は、以下のようにPOSTで投げてあげることでデータが追加登録されます。

curl -X PUT http://localhost:3000/users/6 \
  -H "Content-Type: application/json" \
  -d '{"name":"New User","city":"Osaka","role":"Senior Engineer","age":32}'

AzureでCosmos DBを使う

Azure Cosmos DB の作成

ここでは以下のように作成しました。

項目 入力値
Workload Type Learning
サブスクリプション <自分のPAYGサブスクリプション>
リソースグループ (新規) mvp-dev
アカウント名 mycosmosdb-taiji
場所 Japan East
容量モード サーバーレス

Screenshot 2026-04-02 at 16.58.01.png

内容を確認して作成ボタンをクリックします。
Screenshot 2026-04-02 at 16.58.32.png

デプロイが進行中です。
Screenshot 2026-04-02 at 16.58.56.png

デプロイが完了しました。
Screenshot 2026-04-02 at 17.00.53.png

後ほどここに表示されているURIを使うので、すぐに確認できるようにしておいてください。
Screenshot 2026-04-02 at 17.02.30.png

後ほどここに表示されているPRIMARY KEYを使うので、すぐに確認できるようにしておいてください。
Screenshot 2026-04-02 at 17.03.22.png

コンテナー(データベース)とデータの作成

ローカルでやったのと同じ用に、Data Explorerからデータベースを作成します。

Screenshot 2026-04-02 at 17.07.55.png

ここではローカルと同じく以下の値を設定しました。

項目 入力値
Database id myDatabase(Create new)
Container id myContainer
Partition key /id

Screenshot 2026-04-02 at 17.08.51.png

コンテナーが作成されたことが確認できました。
Screenshot 2026-04-02 at 17.09.44.png

データの投入

Azureに作成したCosmos DBのコンテナにデータを投入します。
先ほど作成したindex2.jsを使いましょう。
index2.jsの接続設定の部分のURIとプライマリーキーの値を、Azure上に作成したCosmos DBのURIとプライマリーキーに置き換えてください。

index2.js
const { CosmosClient } = require("@azure/cosmos");

const endpoint = "<Azure Cosmos DB で発行されたURI>";
const key = "<Azure Cosmos DB で発行されたプライマリキー>";

const client = new CosmosClient({ endpoint, key });

async function main() {
 以後省略

index2.js を実行します。
データが投入され、いくつかのテストクエリーが実行されたことがターミナル上で確認できました。
Screenshot 2026-04-02 at 17.16.35.png
Screenshot 2026-04-02 at 17.16.43.png

登録データの確認

Azureのデータエクスプローラーで、先ほど登録したデータが取得できるか確認します。
コンテナー下のItemsの表示を更新すると、レコードが5件登録されていることが確認できました。
Screenshot 2026-04-02 at 17.16.58.png

Web APIの確認

こちらも同じくapp.jsの接続設定の部分をAzure側のURIとプライマリーキーに置き換えます。

app.js
const express = require("express");
const { CosmosClient } = require("@azure/cosmos");

const app = express();
app.use(express.json());

// Cosmos DB 接続設定
const client = new CosmosClient({
  endpoint: "<Azure Cosmos DB で発行されたURI>",
  key: "<Azure Cosmos DBで発行されたプライマリキー>"
});
const container = client.database("myDatabase").container("myContainer");
 以後省略

app.js を実行してサーバーを起動します。
Screenshot 2026-04-02 at 17.17.16.png

エンドポイントにcurlでリクエストを送ると正常に結果を返してくれました。
Screenshot 2026-04-02 at 17.17.32.png

おまけ - DatadogのCosmos DBモニタリング

Datadogでは、Integrationのための入口がたくさん用意されています。(現在1000サービス・機能以上)

Azureのアカウント認証でIntegrationする

DatadogはAzureの各サービスのIntegrationをサポートしています。アカウント認証ベースでつなぐことができ、Teraformなんかも利用可能です。 AzureそのものをIntegrationすることで、ぶら下がっている各機能のモニタリングも開始することができます。

Screenshot 2026-04-03 at 18.50.18.png

DatadogのダッシュボードでCosmos DBのテレメトリデータを確認する

Integrationが完了すると、デフォルトで取得できるテレメトリデータを監視するためのダッシュボードを自動で作成してくれます。 もちろんカスタマイズ可能なので、見やすいように見出しラベルやレイアウトを変更するのも良いと思います。 スクラッチで自分で1から作成することもできます。

Screenshot 2026-04-03 at 18.52.00.png

まとめ

データベースって、作成するのも使うのも、作り方やクエリーのお作法が分からないと触ってみるのも億劫になりがちかなと思います。 特にRDBの経験が長くNoSQL系を触ったことない人は顕著かもしれません。(RDBが面倒ですからねー)
まあ、ですが、使ってみたら以外と簡単なものが多いと思うので、まずは単純なCRUDのテストレベルでも、触ってみると面白い発見があるかもしれませんね。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?