DatabaseMongoDBNode.js

ExpressとMongoDBの連携

はじめに

最近バックエンド側でExpressを触り始めたのでMongoDBとの接続をやってみる。

環境

  • Windows 10 64bit
  • Node.js:19.1.0
  • Express:4.18.2
  • MongoDB :6.0.8
  • MongoDB Compass:1.39.4

前準備

プロジェクトのセットアップ

まず、任意の名前でNode.jsプロジェクトをセットアップする。

mkdir express_connect_mongodb_sample
cd express_connect_mongodb_sample
npm init -y

MongoDBセットアップ

MongoDBのインストール

MongoDBをインストールし、MongoDBサーバを起動する。

ダウンロードは公式サイトからできる。インストールと起動の詳細手順については、MongoDBの公式ドキュメンテーションを参照。

MongoDB Compassのインストール

MongoDB Compassとは、MongoDBの操作をGUIで行えるツールになる。

ダウンロードはここからできる。

インストールした起動して、ローカルのMongoDBが正常に起動していれば、 Connect で接続できる

Databaseの作成

この後ExpressでMongoDBからデータを引っ張ってこれるようにデータベースを作成しておく。

今回、 DBはHelloMongo で、Collectionは users を作っておく。

これでDB側準備は完了したので、次はExpress側を設定していく。

Expressサーバのセットアップ

ライブラリのインストール

前準備で作成したプロジェクトにexpressとMongooseをインストールする

Mongooseとは、Node.js環境でMongoDBとの接続とデータモデリングを行うためのライブラリになる

次のコマンドでインストールする

npm install express mongoose

Expressアプリケーションのセットアップ

app.jsファイルを作成する。

const express = require("express");
const app = express();

// POSTリクエストを処理するためのミドルウェア
app.use(express.json());

// ルートエンドポイントの設定
app.get("/", (req, res) => {
  res.send("Hello Express!");
});

// サーバーの起動
const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

Mongooseのセットアップ

app.jsにMongoose用の設定を追記する。

const mongoose = require("mongoose");

// MongoDBに接続
const DATABASE_NAME = "HelloMongo"; // ★要修正

mongoose
  .connect(`mongodb://127.0.0.1:27017/${DATABASE_NAME}`, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  })
  .then(() => {
    console.log("Connected to MongoDB");
  })
  .catch((err) => {
    console.error("Error connecting to MongoDB:", err);
  });

mongoose.connectメソッドを使用してMongoDBに接続し、接続が成功するとConnected to MongoDBというメッセージが表示される。

なので、Expressサーバを起動して上記メッセージがコンソールに出力されればここまではOK!

> node app.js
Server is running on port 3000
Connected to MongoDB

DB操作

ExpressアプリケーションからMongoDBに繋がったので、データベース操作を行えるようにする。

詳細は公式ドキュメントに書かれているのでここではざっくりの流れだけ。

モデルの定義

モデルとは、MongoDBデータベース内のコレクション(テーブル)を表現し、このモデルを使ってデータベース操作を行うためのJavaScriptのオブジェクトになる。

今回はCollectionに users を作ったので名前(name)と年齢(age)だけを持つシンプルなモデルを定義する。

const Schema = mongoose.Schema;
const userSchema = new Schema(
  {
    name: String,
    age: Number,
  },
  { timestamps: true }
);

const User = mongoose.model("users", userSchema);

timestampsオプションをtrueにしておくと、次の 2 つのタイプのプロパティをスキーマに自動で追加してくれる

  1. createdAt: この文書がいつ作成されたかを表す日付
  2. updatedAt: このドキュメントが最後に更新された日を表す日付

CRUD操作

アプリケーション・エンドポイント (URI) と、クライアントリクエストに対するそれらのレスポンスの定義である ルーティング の設定を書いていく。

Create(POSTメソッド)

// CREATE(post)
app.post("/users", async (req, res) => {
  try {
    const newUser = new User(req.body);
    await newUser.save();

    res.json({ message: "ユーザが登録されました。", user: newUser });
  } catch (error) {
    res.status(500).json({ error: "ユーザの登録に失敗しました。" });
  }
});

Read(GETメソッド)

// READ(get)
// ex1. 全件取得
app.get("/users", async (req, res) => {
  try {
    const users = await User.find();
    res.json(users);
  } catch (error) {
    res.status(500).json({ error: "ユーザの取得に失敗しました。" });
  }
});

// ex2. IDに紐づくレコード取得
app.get("/users", async (req, res) => {
  try {
    const userId = req.params.userId;
    const user = await User.findById(userId);
    res.json(user);
  } catch (error) {
    res.status(500).json({ error: "ユーザの取得に失敗しました。" });
  }
});

Update(PATCHメソッド)

// UPDATE(patch)
app.patch("/users/:userId", async (req, res) => {
  try {
    const userId = req.params.userId;
    const updateFields = req.body;

    // ユーザを更新
    const updatedUser = await User.findByIdAndUpdate(
      userId,
      { $set: updateFields },
      { new: true }
    );
    if (!updatedUser) {
      return res.status(404).json({ message: "ユーザが見つかりません。" });
    }

    res.json({ message: "ユーザが更新されました。", user: updatedUser });
  } catch (error) {
    res.status(500).json({ error: "ユーザの更新に失敗しました。" });
  }
});

Delete(DELETEメソッド)

// DELETE(delete)
app.delete("/users/:userId", async (req, res) => {
  try {
    const userId = req.params.userId;
    const deletedUser = await User.findByIdAndDelete(userId);

    if (!deletedUser) {
      return res.status(404).json({ message: "ユーザが見つかりません。" });
    }

    res.json({ message: "ユーザが削除されました。", user: deletedUser });
  } catch (error) {
    res.status(500).json({ error: "ユーザの削除に失敗しました。" });
  }
});

動作確認

次のコマンドでサーバーを起動する

node app.js

任意のツールを使って、作成したAPIエンドポイントを呼び出してみる。

CREATE

Request

Response

  • HTTPステータスコード:200
  • Body: { "message": "ユーザが登録されました。", "user":{ "name": "Ashitaka", "age": 17, "_id": "6514c9621bbdbfbd1c8a9d3d", "createdAt": "2023-09-28T00:31:30.187Z", "updatedAt": "2023-09-28T00:31:30.187Z", "__v": 0 } }

READ

Request

Response

  • HTTPステータスコード:200
  • Body [ { "_id": "6514c9621bbdbfbd1c8a9d3d", "name": "Ashitaka", "age": 17, "createdAt": "2023-09-28T00:31:30.187Z", "updatedAt": "2023-09-28T00:31:30.187Z", "__v": 0 } ]

UPDATE

Request

Response

  • HTTPステータスコード:200
  • Body { "message": "ユーザが更新されました。", "user": { "_id": "6514c9621bbdbfbd1c8a9d3d", "name": "Ashitaka2", "age": 19, "createdAt": "2023-09-28T00:31:30.187Z", "updatedAt": "2023-09-28T13:32:58.133Z", "__v": 0 } }

DELETE

Request

Response

  • HTTPステータスコード:200
  • Body { "message": "ユーザが削除されました。", "user": { "_id": "6514c9621bbdbfbd1c8a9d3d", "name": "Ashitaka2", "age": 19, "createdAt": "2023-09-28T00:31:30.187Z", "updatedAt": "2023-09-28T13:32:58.133Z", "__v": 0 } }

ソースコード

今回作ったプロジェクトは次のGithubで管理

GitHub - ashitaka1963/express_connect_mongodb_sample at 0f3c27ed5e373db5ef7062a6912db601242a981b

おわりに

無事にExpresからMongoDBへのCRUD操作を行うことができた。

今回はapp.jsにモデル定義もルーティング定義もすべて詰め込んでいるので、次はモジュール単位のルートハンドラを使ってコードを分割してみる。