--- tags: Node.js 直播班 - 2023 春季班 --- # 第二週 - Node.js NPM 整合 MongoDB 1. 錄影 2. 提醒關於之後的錄影檔都會如何存放 3. [Adobe XD 設計稿](https://xd.adobe.com/view/c0763dbe-fc15-42e8-be0b-8956ed03e675-9525/grid) 4. [講義簡報](https://whimsical.com/mongoose-YKTKL5aF4pHQbkemgQTMZH) 5. [六角後端鬼故事傳奇 00:00~10:00](https://courses.hexschool.com/courses/node-js-20223/lectures/45500860) ## 講解大綱 * Mongoose 講解 * Schema 設計 * 何謂 Model? * 第二週主線任務設計 ## 公布最終作業使用者故事 1. 此為 NFT 會員制的動態牆,僅有限量 VIP 可以加入討論 2. 在 NFT 合約上,有限制永久只有 500 位會員參與此平台 ## NPM * dotenv:環境變數 * [Mongoose](https://mongoosejs.com/) ## 常見 Mongoose 指令 ### 連線語法 ```=javascript const http = require('http'); const mongoose = require('mongoose'); mongoose .connect("mongodb://localhost:27017/testPost") .then(() => console.log('資料庫連接成功')); // schema 開始 // schema 結束 const requestListener = async(req, res)=>{ res.end(); } const server = http.createServer(requestListener); server.listen(3000); ``` > mongodb://localhost:27017/posts ### 建立 Schema ```=javascript const postSchema = new mongoose.Schema( { content: { type: String, required: [true, 'Content 未填寫'] }, image: { type:String, default:"" }, createdAt: { type: Date, default: Date.now(), select: false }, name: { type: String, required: [true, '貼文姓名未填寫'] }, likes: { type:Number, default:0 } } ); const Post = mongoose.model('Post', postSchema); const init = async()=>{ const AllPost = await Post.find(); console.log(AllPost) } init(); ``` ### CURD 語法 * 新增:[Model.create()](https://mongoosejs.com/docs/api/model.html#model_Model.create) * 刪除:[Model.findByIdAndDelete()](https://mongoosejs.com/docs/api/model.html#model_Model.findByIdAndDelete) * 更新:[Model.findByIdAndUpdate()](https://mongoosejs.com/docs/api/model.html#model_Model.findByIdAndUpdate) * 查詢:[Model.find()](https://mongoosejs.com/docs/api/model.html#model_Model.find) ``` await Post.findByIdAndUpdate(id,editContent) // 更新單筆 await Post.deleteMany({}); //刪除全部 await Post.findByIdAndDelete(id); // 刪除單筆 ``` :::spoiler 完整 Code ## code ```=JavaScript const http = require('http'); const mongoose = require('mongoose'); mongoose .connect("mongodb://localhost:27017/testPost") .then(() => console.log('資料庫連接成功')); const postSchema = new mongoose.Schema( { content: { type: String, required: [true, 'Content 未填寫'] }, image: { type:String, default:"" }, createdAt: { type: Date, default: Date.now(), select: false }, name: { type: String, required: [true, '貼文姓名未填寫'] }, likes: { type:Number, default:0 } } ); const Post = mongoose.model('post', postSchema); const requestListener = async(req, res)=>{ const headers = { 'Access-Control-Allow-Headers': 'Content-Type, Authorization, Content-Length, X-Requested-With', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'PATCH, POST, GET,OPTIONS,DELETE', 'Content-Type': 'application/json' } let body = ""; req.on('data', chunk=>{ body+=chunk; }) if(req.url=="/posts" && req.method == "GET"){ const post = await Post.find(); res.writeHead(200,headers); res.write(JSON.stringify({ "status": "success", post })); res.end(); }else if(req.url=="/posts" && req.method == "POST"){ req.on('end',async()=>{ try{ const data = JSON.parse(body); if(data.content !== undefined){ const newPost = await Post.create( { name: data.name, content: data.content, } ); res.writeHead(200,headers); res.write(JSON.stringify({ "status": "success", "data": newPost, })); res.end(); }else{ res.writeHead(400,headers); res.write(JSON.stringify({ "status": "false", "message": "欄位未填寫正確,或無此 todo ID", })); res.end(); } }catch(error){ res.writeHead(400,headers); res.write(JSON.stringify({ "status": "false", "message": error, })); res.end(); } }) }else if(req.url.startsWith("/posts/") && req.method=="DELETE"){ const id = req.url.split('/').pop(); await Post.findByIdAndDelete(id); res.writeHead(200,headers); res.write(JSON.stringify({ "status": "success", "data": null, })); res.end(); }else if(req.method == "OPTIONS"){ res.writeHead(200,headers); res.end(); }else{ res.writeHead(404,headers); res.write(JSON.stringify({ "status": "false", "message": "無此網站路由" })); res.end(); } } const server = http.createServer(requestListener); server.listen(3000); ``` ::: ## 本堂作業 設計一個 /posts 路由,設計與 [todolist API 練習](https://discord.com/channels/801807326054055996/1073411249926324234/1075786895914700820) 一樣的設計,並將欄位調整擴充為一則貼文會有的欄位,可觀看第二週直播錄影做為參考。 - 將程式碼上傳 GitHub #### 加分條件 - 請觀看此[範例](https://github.com/gonsakon/nodeweek2-sample),拉到 Model 資料夾來設計 #### **作業分享** 1. 作業:請提供 **GitHub Repo** 連結,並回報到此 [Discord](https://discord.com/channels/801807326054055996/1073411249926324234/1088723579752943637) 作業分享區 ### Render 部署 Node 伺服器 * [Render 伺服器部署 Node.js](https://israynotarray.com/other/20221213/3036227586/) ## Callback 介紹 請寫一篇部落格,解釋何謂 **callback function**,加分題是講解 express middleware 如何透過 callback function 實現 * [Genos - https://stark920.github.io/2022/04/17/JScallback/](https://stark920.github.io/2022/04/17/JScallback/) * [邱繼緯(小麥)0.5本 - 了解 JavaScript 中的 callback function](https://ayugioh2003.github.io/2022/04/callback-function/) * [Han Lai 0.5本 - 淺談 JavaScript Callback Function](https://hackmd.io/@laihan/S1nTlwY49) * [Pon - 0.5本 - 回呼函式(callback function)](https://forest-lunge-74a.notion.site/callback-function-da5ef9fa618b437384e622e19b2d97ea) ## Mock API 介紹 請寫一篇部落格,講解你跟後端合作的時候,用哪個 Mock API 服務,造福大家 * [Albert(炸豆腐) - Mock API 身為前端該了解的知識點 ](https://callum.hashnode.dev/mock-api) * [joe.chang - 別等了!用Mock Service Worker來產生Mock API吧!](https://medium.com/coding-hot-pot/%E5%88%A5%E7%AD%89%E4%BA%86-%E7%94%A8mock-service-worker%E4%BE%86%E7%94%A2%E7%94%9Fmock-api%E5%90%A7-f921ab30d5c7) * [Leo Chuang - 使用Mocks Server快速建立Front-End mock API](https://medium.com/@dennis302218905/%E4%BD%BF%E7%94%A8mocks-server%E5%BF%AB%E9%80%9F%E5%BB%BA%E7%AB%8Bfront-end-mock-api-130a1876832b)