# 第二週 - 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. 六角後端鬼故事傳奇 ## 講解大綱 * Mongoose 講解 * Schema 設計 * 何謂 Model? * 第二週主線任務設計 ## 公布最終作業使用者故事 1. 此為 NFT 會員制的動態牆,僅有限量 VIP 可以加入討論 2. 在 NFT 合約上,有限制永久只有 500 位會員參與此平台 ## NPM * dotenv:環境變數 * [Mongoose](https://mongoosejs.com/) ## 常見 Mongoose 指令 ### 連線語法 若 localhost 不行,可改為 `mongodb://127.0.0.1:27017/testPost` ```=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); ``` ::: ## 本堂作業 * 講解主線任務