Expense Tracker Web app based on todo-list concept with MongoDB, Express, passport

楊雅婷(Yang Ya-Ting)
Yang Yating
Published in
8 min readNov 23, 2020

Background information: 2019年末開始Alpha Camp的課程,從學期1開始,一路經歷學期2–1, 2–2, 2–3,中間休息三個月準備GRE考試,今年十一月開始最後階段-學期三的課程。

你為何會選擇這個專案?

相較於學期一和二是帶領我們從框架、基本語法、認識資料庫等面向了解前、後端網路開發,學期三將之前教案的內容統合起來,一口氣串接起前後端,建構出更完整的網頁開發視角。而在開發網頁功能時,很大一部分都與CRUD(create, read, update and delete)功能相關,最經典的使用便是Todo-list的實作,從小到採購清單,或大到專案管理都可使用到Todo-list的概念,功能可單純也可複雜,因此作為練手的第一個專案,我想沿用todo-list的觀念,將之套用在記帳(Expense Tracker)專案,不僅可協助我更熟練CRUD的設定、前端切版、模板操作、路由設定等,也會帶到資料庫操作,將前後端串起,深化全端學習,也期待透過記帳專案,打造自己也很喜歡使用的web app。

你使用了什麼技術?

專案使用Node.js搭配Express框架,透過Express,可以快速的建構起路由,設定request, response,並且透過handlebars渲染對應的畫面。為符合Restful API,使用method override作為其中一項middleware。

登入驗證功能則引入session, passport, passport-facebook,協助使用者可以保持登入狀態、使用facebook帳號登入、登出等,優化使用者體驗。而串接資料庫方面,則採用mongodb,搭配mongoose及robot 3T。完整清單請參考:

  • “bcryptjs”: “².4.3”,
  • “body-parser”: “¹.19.0”,
  • “connect-flash”: “⁰.1.1”,
  • “dotenv”: “⁸.2.0”,
  • “express”: “⁴.17.1”,
  • “express-handlebars”: “⁵.2.0”,
  • “express-session”: “¹.17.1”,
  • “method-override”: “³.0.0”,
  • “moment”: “².29.1”,
  • “mongoose”: “⁵.10.13”,
  • “passport”: “⁰.4.1”,
  • “passport-facebook”: “³.0.0”,
  • “passport-local”: “¹.0.0”

哪部分你相對能掌握?

從學期二開始就陸續接觸Express, handlebars, bootstrap, Restful, CRUD,猶記第一次接觸node.js, 框架等概念時,感覺非常陌生,花了許多查詢資料,試圖想理解網路運作的原理(V8引擎等等),到現在已經可以熟練的初始化專案,並且引入middleware及一氣呵成的做完所有設定,可以明顯感受到對這些工具、功能有較高的掌握度。

而驗證、登入、密碼保護幾乎已經是所有網站的標配功能,從了解cookie概念開始,一路到設定session, passport, passport-facebook,都帶到更多網路應用的原理,程式碼也相對複雜,這學期第一次接觸花了較多時間理解觀念。有些抽象,不過相信之後多使用幾次也會漸漸比較了解。

哪裡花了最多時間?

1. 處理mongodb date資料

使用者新增一筆支出時,需要填寫花費名稱(name), 金額(amount), 日期(date), 店家(merchant)以及選擇類別(category)。

日期的格子設定為type=’date’,因此存入資料庫時,便是以Iso Date格式存入。當資料從資料庫,渲染到handlebars模板時,會長這樣:2020–11–19 17:18:38.614Z GMT+8,而除了日期之外,小時、分鐘及GMT+8都是不需要顯示的資料,因此要如何在渲染到handlebars之前,留下必要的字串,拿掉不需要的資訊,就是這階段面臨的難題。

一開始都專注在要如何將ISO Date格式轉為字串,再將不需要的資料去除(splite),查閱許多資料都沒能成功,都是卡在轉為字串不成功,大概卡了一兩天,偶然看到AC前學長的分享,透過moment.js,成功將ISO Date客製化格式(format)。只用一行程式碼便解決問題。

let isoDate = item.date
item.date = moment(isoDate).format(‘YYYY-MM-DD’)

回頭反思會卡這麼久,第一是搜尋關鍵字下得不夠精確,以至於我前面一兩天的搜尋結果都是偏向如何將字串資料轉為date格式存入資料庫,而非date資料如何轉為字串,第二是,不了解如何正確、快速的閱讀官方文件,其實在搜尋過程不止一次有出現moment.js的關鍵字,但因為對這個函式庫不熟悉,再加上不熟悉閱讀官方文件,以至於忽略了這項符合我需求的功能。

2. 以類別(category)及用份(month)篩選資料

使用者可透過類別及月份篩選出對應的支出項目,並顯示篩選後資料的總金額。

一開始的方向都是希望在資料庫就做到filter資料的功能,mongodb官方也有$filter的文件可參考,不過看起來需搭配aggregate(聚合?)使用,參考了其他同學的程式碼,寫法跟官方文件好像也不太一樣,卡了一兩天,多次嘗試都沒辦法篩選出我需要的資料,因此先不使用filter,而是採用較為土法煉鋼方式,先將所有資料載入,接著使用forEach遍歷每一個資料的category&date,篩出合適資料,再傳給前端。

目前功能測試都可以順利執行,不過擔心日後資料量一多,forEach遍歷可能會導致效能變差,因此雖先以此方式暫代filter,日後優化程式碼時,還是希望可以在資料庫就先篩選再傳進來。

過程中碰到什麼困難?

不熟悉及不習慣閱讀官方文件是我在這個專案上遇到比較大的困難,例如moment.js, mongodb的資料庫語法等,後來能夠實際應用都是參考其他前人的中文分享,因此我想訓練自己閱讀官方文件的能力,一開始可能先中文搭配英文,試圖了解官方文件的邏輯,之後再嘗試自行理解,這也是身為工程師很重要且不可或缺的能力之一。

過程中你有對哪個技術有特別深刻的學習?

#1對網頁開發建構出完整的藍圖

這次從專案初始化、路由設定、模板建立以及連線資料庫,到將專案推上heroku,都刻意讓自己慢一點,並將檔案之間的flow串接起來,確認理解功能後再往下推進。比起上學期對所有內容的建構都朦朦懂懂,這學期能夠更請處說明網頁是如何運作、每一個js檔案扮演的角色是什麼,以及較不會迷失在眾多的檔案海中,一不小心就迷路。期待透過刻意練習,能夠讓自己更熟練目前已經掌握的知識,對不熟悉的內容也可漸漸上手。

#2學習更多語法的應用

開發專案最期待的莫過於開發自身也很喜歡的功能和介面,功能方面,為了打造顯示時間、新增篩選功能,真的花了很多時間在找尋資料,過程雖然會因為自己理解不足而備感壓力和挫折,但最後能夠理解並且應用,或是找到替代方案的成就感也讓我印象深刻,並持續鼓勵自己不要放棄。

在設計自己喜歡的UI時,我先在Pinterest找可參考的介面,再將多個元素貼到keynote,拼湊起來,當有一個清楚的方向再著手切版時,會更有方向性,也不會想到什麼才改什麼,讓開發更有效率。

Next Step

接下來,還想要在記帳app新增&優化以下功能:

  • 使用者可以篩選start date, end date
  • 使用者可以新增收入資料
  • 使用者可以看到本月收支總和
  • 使用者可以依照屬性排序(name, category and more)
  • 每項分類(category)的花費總合

--

--

楊雅婷(Yang Ya-Ting)
Yang Yating

Information Management Grad Student @ University of Maryland, College Park|Full-Stack Engineer