前回は、mongoose をセッティングしました。

今回は、mongoose を使ってブラウザに表示や、データを編集や削除します。

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

views/index.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

<!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

<!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

<!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

const express = require("express")
const app = express()
const path = require("path")
const mongoose = require("mongoose")

app.set("view engine", "ejs")
app.set("views", "views")

const menuRoutes = require("./routes/index.js")
const menus = require("./routes/menu.js")

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>")
})

mongoose
  .connect(
    "mongodb+srv://Nao:Erm21A7RApOToQmH@cluster0.q1atv.mongodb.net/myFirstDatabase?retryWrites=true&w=majority"
  )
  .then(() => {
    app.listen(8000)
    console.log("Server is running ...")
  })
  .catch(err => {
    console.log(err)
    throw err
  })

models/menu.js

const mongoose = require("mongoose")
const Schema = mongoose.Schema

const menuShema = new Schema({
  title: String,
  description: String,
})

module.exports = mongoose.model("Menu", menuShema)

controllers/menus.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: title, description: 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)
    .then(menu => {
      res.render("menu-edit", {
        menu: menu,
        pageTitle: "メニュー内容編集",
      })
    })
    .catch(err => {
      console.log(err)
    })
}

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)
  }
}

routes/index.js

const express = require("express")
const router = express.Router()

const menuController = require("../controllers/menus")

router.get("/", menuController.getAddMenus)

module.exports = router

routes/menu.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

ブラウザにデータを表示する

まずは、ブラウザにメニュー内容を表示します。

controllers の menus.js を開きます。

データの一覧を取得したい時、MongoDB ではMenuクラスのfetchAllを使っていました。

mongoose では、findを使ってデータの一覧を取得することができます。

getAddMenusfetchAllfindに変更しましょう。

exports.getAddMenus = (req, res, next) => {
  Menu.find()
    .then(menus => {
      res.render("index", {
        pageTitle: "メニュー一覧",
        menus,
      })
    })
    .catch(err => {
      console.log(err)
    })
}

ブラウザで確認してみましょう。

image2

image3

MongoDB のデータが、ブラウザに表示されました。

image4

image5

データも追加できています。

メニューの詳細画面を表示する

次に、MongoDB から単一のデータを取得し、メニュー画面に表示させます。

menus.js のgetMenuで、MenuクラスのfetchMenuを使っていました。

mongoose では、findByIdで単一データを取得することができます。

getMenu のfetchMenufindByIdへ変更しましょう。

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

ブラウザで『朝定食』の詳細画面へ遷移してみます。

image6

image7

詳細画面へ遷移することができました。

データを削除する

詳細画面へ遷移することができたので、mongoose で MongoDB のデータを削除します。

menus.js のgetMenuで、MenuクラスのdeleteMenuを使っていました。

mongoose では、findByIdAndRemoveで単一データを削除することができます。

MenudeleteMenufindByIdAndRemoveへ修正します。

exports.postDeleteMenu = (req, res, next) => {
  const id = req.body.menuId
  Menu.findByIdAndRemove(id)
    .then(res.redirect("/"))
    .catch(err => {
      console.log(err)
    })
}

では、『朝定食』の削除ボタンをクリックしてみます。

image8

image9

『朝定食』が削除されました。

image10

MongoDB のデータも削除されています。

データを編集する

最後に、メニュー内容を編集します。

menus.js のgetEditMenuにあるfetchMenuを find へ変更します。

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

postEditMenu の try より先を削除します。

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

データを更新するときは、mongoose のupdateOneを使います。

updateOneの中は、_idtitledescriptionのスキーマを作成しましょう。

exports.postEditMenu = (req, res, next) => {
  const id = req.body.id
  const updateTitle = req.body.title
  const updateDescription = req.body.description

  Menu.updateOne(
    {
      _id: id,
    },
    {
      title: updateTitle,
      description: updateDescription,
    }
  )
}

データの更新ができた場合は、ホーム画面へ遷移します。

また、失敗した場合は、console.logでエラーを返します。

exports.postEditMenu = (req, res, next) => {
  const id = req.body.id
  const updateTitle = req.body.title
  const updateDescription = req.body.description

  Menu.updateOne(
    {
      _id: id,
    },
    {
      title: updateTitle,
      description: updateDescription,
    }
  )
    .then(() => res.redirect("/"))
    .catch(err => console.log(err))
}

これで完成しましたので、動作確認してみます。

image11

image12

『ミックスグリル定食』の編集をクリックします。

image13

編集画面へ遷移することができました。

メニュー名を変更して、『メニューを更新する』ボタンをクリックすると、

image14

image15

メニュー名を更新することができました。

image16

MongoDB のデータも更新されています。

ブログ一覧