【Node.js】ExpressでMongoDBのデータを編集する
Node.js

【Node.js】ExpressでMongoDBのデータを編集する

作成日:2021年11月03日
更新日:2021年11月04日

前回は、Express で MongoDB のデータを削除しました。

nodejs-mongodb-delete

【Node.js】ExpressでMongoDBのデータを削除する

今回は、Express で MongoDB のデータを編集します。

コードは、前回のコードを使用します。

views/index.ejs

ejs
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%= pageTitle %></title>
</head>
<body>
<main>
<h1>メニュー</h1>
<p>メニュー一覧</p>
<% if(menus.length > 0) { for (let menu of menus){ %>
<p><%= menu.title %></p>
<a href="/menu/<%= menu._id %>">詳細画面</a>
<div>
<a href="/edit-menu/<%= menu._id %>">編集</a>
<form action="/delete-menu" method="POST">
<input type="hidden" value="<%= menu._id %>" name="menuId" />
<button type="submit">削除</button>
</form>
</div>
<%} %> <% } else { %>
<p>注文がありません</p>
<% } %>
</main>
</body>
</html>

views/menu.ejs

ejs
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/css/styles.css" />
<title><%= pageTitle %></title>
</head>
<body>
<main>
<form action="/menu" method="POST">
<div class="form-control">
<label for="title">メニュー名</label>
<input type="text" name="title" />
</div>
<div class="form-control">
<label for="description">内容</label>
<input type="text" name="description" />
</div>
<button type="submit">メニューを追加する</button>
</form>
</main>
</body>
</html>

views/menu-detail.ejs

ejs
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%= pageTitle %></title>
</head>
<body>
<main>
<h1><%= menu.title %></h1>
<p><%= menu.description %></p>
</main>
</body>
</html>

views/menu-edit.ejs

ejs
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/css/styles.css" />
<title><%= pageTitle %></title>
</head>
<body>
<main>
<form action="/edit-menu" method="POST">
<input type="hidden" name="id" value="<%= menu.id %>" />
<div class="form-control">
<label for="title">メニュー名</label>
<input type="text" name="title" value="<%= menu.title %>" />
</div>
<div class="form-control">
<label for="description">内容</label>
<input
type="text"
name="description"
value="<%= menu.description %>"
/>
</div>
<button type="submit">メニューを更新する</button>
</form>
</main>
</body>
</html>

index.js

js
const express = require("express");
const app = express();
const path = require("path");
app.set("view engine", "ejs");
app.set("views", "views");
const menuRoutes = require("./routes/index.js");
const menus = require("./routes/menu.js");
const dbConnect = require("./utils/database").dbConnect;
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, "public")));
app.use("/", menus);
app.use(menuRoutes);
app.use((req, res, next) => {
res.status(404).send("<h1>ページが見つかりません</h1>");
});
dbConnect(() => {
app.listen(8000, () => console.log("Server is running ..."));
});

models/menu.js

js
const mongodb = require("mongodb");
const getDb = require("../utils/database").getDb;
const fs = require("fs");
const path = require("path");
const menus = [];
module.exports = class Menu {
constructor(title, description) {
this.title = title;
this.description = description;
}
save() {
return getDb()
.collection("menu")
.insertOne(this)
.then((res) => console.log(res))
.catch((err) => console.log(err));
}
static fetchAll() {
return getDb()
.collection("menu")
.find()
.toArray()
.then((menus) => {
return menus;
})
.catch((err) => console.log(err));
}
static fetchMenu(id) {
return getDb()
.collection("menu")
.find({ _id: new mongodb.ObjectId(id) })
.next()
.then((menu) => {
return menu;
})
.catch((err) => console.log(err));
}
static deleteMenu(id) {
return getDb()
.collection("menu")
.deleteOne({ _id: new mongodb.ObjectId(id) })
.then((menu) => {
console.log(menu);
})
.catch((err) => console.log(err));
}
};

controllers/menus.js

js
const Menu = require("../models/menu");
exports.getAddMenu = (req, res, next) => {
res.render("menu", { pageTitle: "メニュー追加" });
};
exports.postAddMenu = (req, res, next) => {
const title = req.body.title;
const description = req.body.description;
const menu = new Menu(title, description);
menu.save();
res.redirect("/");
};
exports.getAddMenus = (req, res, next) => {
Menu.fetchAll()
.then((menus) => {
res.render("index", {
pageTitle: "メニュー一覧",
menus,
});
})
.catch((err) => {
console.log(err);
});
};
exports.getMenu = (req, res, next) => {
const id = req.params.menuId;
Menu.fetchMenu(id)
.then((menu) => {
res.render("menu-detail", {
menu: menu,
pageTitle: "詳細画面",
});
})
.catch((err) => {
console.log(err);
});
};
exports.postDeleteMenu = (req, res, next) => {
const id = req.body.menuId;
Menu.deleteMenu(id)
.then(res.redirect("/"))
.catch((err) => {
console.log(err);
});
};
exports.getEditMenu = (req, res, next) => {
const id = req.params.menuId;
Menu.fetchMenu(id, (menu) => {
res.render("menu-edit", {
menu: menu,
pageTitle: "メニュー内容編集",
});
});
};
exports.postEditMenu = (req, res, next) => {
const id = req.body.id;
const updatedTitle = req.body.title;
const updatedDescription = req.body.description;
const updatedMenu = new Menu(id, updatedTitle, updatedDescription);
updatedMenu.save();
res.redirect("/");
};

routes/index.js

js
const express = require("express");
const router = express.Router();
const menuController = require("../controllers/menus");
router.get("/", menuController.getAddMenus);
module.exports = router;

routes/menu.js

js
const express = require("express");
const router = express.Router();
const menuController = require("../controllers/menus");
router.get("/menu", menuController.getAddMenu);
router.get("/menu/:menuId", menuController.getMenu);
router.post("/menu", menuController.postAddMenu);
router.post("/delete-menu", menuController.postDeleteMenu);
router.get("/edit-menu/:menuId", menuController.getEditMenu);
router.post("/edit-menu", menuController.postEditMenu);
module.exports = router;

utils/database.js

js
const mongodb = require("mongodb");
const MongoClient = mongodb.MongoClient;
let _db;
const dbConnect = (callback) => {
MongoClient.connect(
"mongodb+srv://Nao:abcdefgh@cluster0.q1atv.mongodb.net/myFirstDatabase?retryWrites=true&w=majority"
)
.then((item) => {
console.log("MongoDB Connected");
_db = item.db();
callback(item);
})
.catch((err) => {
console.log(err);
throw err;
});
};
const getDb = () => {
if (_db) {
return _db;
}
throw "データベースがありません";
};
exports.dbConnect = dbConnect;
exports.getDb = getDb;

データを編集画面に表示する

まずは、編集をクリックすると、編集画面へ遷移するように修正します。

controllers フォルダの menus.js を開きます。

getEditMenuの中身を削除します。

js
exports.getEditMenu = (req, res, next) => {};

getMenuの中身をコピーして、getEditMenuの中に貼り付けます。

js
exports.getEditMenu = (req, res, next) => {
const id = req.params.menuId;
Menu.fetchMenu(id)
.then((menu) => {
res.render("menu-detail", {
menu: menu,
pageTitle: "詳細画面",
});
})
.catch((err) => {
console.log(err);
});
};

menu-detailmenu-editへ、『詳細画面』を『メニュー内容編集』へ修正します。

js
exports.getEditMenu = (req, res, next) => {
const id = req.params.menuId;
Menu.fetchMenu(id)
.then((menu) => {
res.render("menu-edit", {
menu: menu,
pageTitle: "メニュー内容編集",
});
})
.catch((err) => {
console.log(err);
});
};

編集コントローラーが完成したので、動作確認をやってみます。

『エビフライ定食』の編集をクリックします。

image2

image3

エビフライ定食の編集画面へ遷移しました。

メニュー内容を更新する

次に、『メニューを更新する』ボタンをクリックすると、メニュー内容が更新される様にします。

models フォルダの menu.js を開きます。

Menu クラスにupdateMenuを作成します。

データを更新するするために、idtitledescriptionを渡す様にします。

js
static updateMenu(id, title, description) {
}

deleteMenuの内容をupdateMenuに貼り付けます。

js
static updateMenu(id, title, description) {
return getDb()
.collection("menu")
.deleteOne({ _id: new mongodb.ObjectId(id) })
.then((menu) => {
console.log(menu);
})
.catch((err) => console.log(err));
}

MongoDB を更新するときは、updateOneを使用します。

js
static updateMenu(id, title, description) {
return getDb()
.collection("menu")
.updateOne(
{ _id: new mongodb.ObjectId(id) }
)
.then((menu) => {
console.log(menu);
})
.catch((err) => console.log(err));
}

titledescriptionを更新したい場合、$setを使います。

$setは、指定された値を持つフィールドの値を置き換えます。

js
static updateMenu(id, title, description) {
return getDb()
.collection("menu")
.updateOne(
{ _id: new mongodb.ObjectId(id) },
{ $set: { title, description } }
)
.then((menu) => {
console.log(menu);
})
.catch((err) => console.log(err));
}

以下のコードは、不要になったので削除します。

js
const fs = require("fs");
const path = require("path");
const menus = [];

編集モデルが完成したので、次はコントローラーを編集します。

controllers フォルダの menus.js を開きます。

postEditMenuupdatedMenuを削除します。

js
exports.postEditMenu = (req, res, next) => {
const id = req.body.id;
const updateTitle = req.body.title;
const updateDescription = req.body.description;
res.redirect("/");
};

Menu クラスのupdateMenuを接続します。

更新内容は、idupdateTitleupdateDescriptionを指定します。

js
exports.postEditMenu = (req, res, next) => {
const id = req.body.id;
const updateTitle = req.body.title;
const updateDescription = req.body.description;
Menu.updateMenu(id, updateTitle, updateDescription);
res.redirect("/");
};

trycatchでエラーを取得する様にします。

js
exports.postEditMenu = (req, res, next) => {
const id = req.body.id;
const updateTitle = req.body.title;
const updateDescription = req.body.description;
try {
Menu.updateMenu(id, updateTitle, updateDescription);
res.redirect("/");
} catch (err) {
console.log(err);
}
};

編集コントローラーが完成しました。

最後に、編集画面の id を修正します。

views フォルダの menu-edit.ejs を開きます。

menu.idを、menu._idへ修正します。

ejs
<input type="hidden" name="id" value="<%= menu._id %>" />
```
一通り完了したので、動作確認してみます。
![image4](/images/161-image4.png)
『エビフライ定食』の編集をクリックします。
![image5](/images/161-image5.png)
『エビフライ定食』から『ミックスフライ定食』へ変更します。
![image6](/images/161-image6.png)
『メニューを更新する』ボタンをクリックすると、
![image7](/images/161-image7.png)
メニュー内容を更新することができました。
![image8](/images/161-image8.png)
MongoDB の内容も更新されていました。

© 2024あずきぱんウェブスタジオ