はじめに
最近バックエンド側で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 つのタイプのプロパティをスキーマに自動で追加してくれる
- createdAt: この文書がいつ作成されたかを表す日付
- 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
- Method:POST
- URL:http://localhost:3000/users
- Body:{ "name": "Ashitaka", "age": 17}
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
- Method:GET
- URL:http://localhost:3000/users
- 上記は全件取得時のエンドポイント
- IDでユーザを絞る場合には以下のエンドポイントを利用する。 http://localhost:3000/users/6514c9621bbdbfbd1c8a9d3d ※`6514c9621bbdbfbd1c8a9d3d`はCREATE時に発番されたID
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
- Method:PATCH
- URL:http://localhost:3000/users/6514c9621bbdbfbd1c8a9d3d
- ※
6514c9621bbdbfbd1c8a9d3d
はCREATE時に発番されたID
- ※
- Body:{ "name": “Ashitaka2", "age": 17 }
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
- Method:DELETE
- URL:http://localhost:3000/users/6514c9621bbdbfbd1c8a9d3d
- ※
6514c9621bbdbfbd1c8a9d3d
はCREATE時に発番されたID
- ※
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にモデル定義もルーティング定義もすべて詰め込んでいるので、次はモジュール単位のルートハンドラを使ってコードを分割してみる。