普通文組 2.5

從零開始重寫:餐廳清單(Express版)基礎功能與架構

總結

試著從頭開始重新練習一次 Express、Express handlebars 與 Mongoose 相關內容,本篇筆記主要記錄練習途中遭遇到的問題、解法與日後可能會回頭參考的相關內容

環境

express: 4.17.1
express-fileupload: 1.2.1
express-handlebars: 5.3.2
mongoose: 5.12.14
os: Windows_NT 10.0.18363 win32 x64

app.js

  • 20-21 行:為了處理使用者上傳的餐廳圖片,使用套件express-fileuploadnpm
    • 參考官方示範,HTML 的 form 元素須加上encType="multipart/form-data"才能取到圖片資料
    • 注意:是透過req.files而非req.body來取使用者上傳的圖片資料
    • 取出req.files.<input name>.mimetypereq.files.<input name>.data來存入資料庫
  • 26 行 helpers 部分:本次使用自定義的 helpers 來配合 Express handlebars,接觸過 Vue 的 computed 後比較能理解 helpers 的運作模式了
    • 注意呼叫自定義的 helpers不需要加上#,在模板中直接傳入 helpers 與參數即可,比如:
    • <img src="{{toImage this.image.contentType this.image.data.buffer}}">
    • <option {{ifEquals this ../restaurant.category}}></option>
  • 39 行開始:對比之前的作業多半使用.then()進行串接,本次基本上都改用 await/async 語法糖來處理資料庫端相關的行為
    • await Restaurant.find({ deleteFlag: false }).sort({ _id: -1 }).lean():取所有deleteFlagfalse的內容,並根據_id逆向排列
  • 48 行開始:本次實作出「根據使用者選取的欄位來限制搜尋範圍」之功能,keyword為使用者輸入的關鍵字、field為使用者指定要進行搜尋的欄位範圍
    • 52-53 行:無法在mongoose.find()直接使用 template literal,故改為「建立一個空物件,物件的鍵根據field決定,物件的值為new RegExp(keyword, 'i')」,並將該物件作為條件傳入.find()
    • 57 行:偷懶行為,直接將field的中文對應名稱物件宣告在這邊,並傳入顯示搜尋結果的index模板
  • 第 71 行:await Restaurant.find().distinct('category').lean()
  • 99-104 行:若使用者選擇自行上傳餐廳圖片(if (req.files))的話,取圖片的datamimetype存入 DB 中,若使用者沒有上傳圖片的話,則自動安排一張預設的餐廳圖片 url 給image_url欄位
  • 第 152 行:使用.findOne()來取出document型態的資料,之後才可配合.save()將修改完的資料存回 DB 中
    • Mongoose: Documents vs Models: Document and Model are distinct classes in Mongoose. The Model class is a subclass of the Document class. When you use the Model constructor, you create a new document.
    • When you load documents from MongoDB using model functions like findOne(), you get a Mongoose document back.

DB schema

DB seeder

  • 2-3 行:讀取.json資料
  • 第 15 行開始:改用 async/await 語法糖包裝Restaurant.create()
  • 31 行:seeder 寫入完畢後,呼叫db.close()結束連線

模板部分

{{#if searchCheck}}
<script src="/scripts/searchCheck.js"></script>
{{/if}}

目前僅有//search路由回傳searchCheck: true,故searchCheck.js只會在這兩個頁面被載入

參考文件