iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 16
0
自我挑戰組

如何成為工程師? (從工地到前端工程師)系列 第 16

[Day 16] 我們來學 Node & ExpressJS 吧, 先來個CRUD

  • 分享至 

  • xImage
  •  

背景

我react 學完, 那我想說來學一下後端的技術. 那我選node 因為 node 跟javascript 是一樣的所以我不需要在學一個新的語言. 我可以專心理解後端的技術跟觀念. 所以我們開始吧. 我那時候用Express 做了 blog, 購物車, facebook 聊天機器人, 認證系統

Database NOSQL

NOSQL 代表 Not only SQL, 但是你還是可以用 SQL 的功能譬如 primary key, index, relationships. NOSQL存檔的格式就是JSON格式(key-value pairs). 所以跟 Javascript 還滿合的. 聽說一開始node是沒有支援mysql.

NOSQL 的優點
  1.分散(distributed)-例如有些noSQL可以在不中斷資料庫運行的情況擴充database空間

  2.欄位自由(schema-free)-你不用在一開始即規劃好每個資料庫內要有什麼欄位

  3.資料格式的一致(eventually consistent)-這是分散式系統的概念,簡單地來說分散式系統node會很頻繁地加入或退出,所以node在進出同時和進出後也要維持資料不會出錯

  4.支援大容量的資料庫運算-有時可能會到以TB為單位

適合用在: 大數據, 讀很快, 寫很慢
我在demo 裡面我會用mongoose, mongoose 是一個mongodb的ORM. 基本上會提供一些方便的API讓我們更容易寫SQL指令

框架 express

ExpressJS 是nodeJS 裡面最普遍的框架. 其實很多其他的框架的底成也是用express 寫的(Sail.js, Keyjones.js). Express 是一個很輕量的框架, 很多東西都要自己來, 但是這樣也不錯就是我們可以真的了解code實在做什麼.

教學

我會用我的blog 專案來demo. 連結

  1. 安裝mongoose

    npm install mongoose --save
    
  2. 在App.js設定連結

    // app.js
    const mongoose = require('mongoose')
    ...
    mongoose.Promise = global.Promise;
    mongoose.connect('mongodb://localhost/blogv2')
    
  3. 用 model/post.js 建立一個 schema(欄位)

    // models/post.js
    let mongoose = require('mongoose')
    // Post Schema
    let postSchema = mongoose.Schema({
      title: { type: String, required: true },
      body: { type: String, required: true }
    })
    let Post = module.exports = mongoose.model('Post', postSchema)
    
  4. 去mongo shell 輸入假資料

    db.articles.insert({title: "Article one", body: "this is article one"})
    
  5. 在routes/posts.js 寫出相對的CRUD 路徑

    // posts.js
    var express = require('express');
    var router = express.Router();
    // Bring in Models
    let Post = require('../models/post')
    /* GET Posts . */
    router.get('/', function(req, res, next) {
      Post.find({}, function(err, posts){
        if (err) {
          console.log(err)
        } else {
          res.render('posts/index', { posts: [...posts] });
        }
      })
    });
    // GET Add Post Route
    router.get('/add', function(req, res){
      res.render('posts/addPost')
    })
    // POST Add Post Route
    router.post('/add', function(req, res){
      var post = new Post({
        title: req.body.title,
        body: req.body.body
      });
      post.save(function(err, resp) {
        if (err) {
          console.log(err);
          res.send({
            message: 'something went wrong'
          });
        } else {
          res.redirect('/posts')
        }
      });
    })
    // Get Show Post"/posts/<%= post._id%>"
    router.get('/:id', function(req,res){
      Post.findById(req.params.id, function(err, post){
        res.render('posts/showPost',{
          post: post,
        })
      })
    })
    // Get Edit Form
    router.get('/edit/:id', function(req,res){
      Post.findById(req.params.id, function(err, post){
        res.render('posts/editPost',{
          post: post
        })
      })
    })
    //Post Edit Route
    router.post('/edit/:id', function(req, res){
      let post = {}
      post.title = req.body.title
      post.body = req.body.body
      let query = { _id: req.params.id }
      Post.update(query, post, function(err){
        if(err){
          console.log(err)
          return
        } else {
          res.redirect('/posts')
        }
      })
    })
    // DELETE Route
    router.delete('/delete/:id', function(req, res){
      let query = { _id: req.params.id}
      Post.remove(query, function(err){
        if(err){
          console.log()
        }
        res.send('Success')
      })
    })
    
  6. 產出需要的view
    index.ejs
    addPost.ejs
    editPost.ejs
    showPost.ejs

    // index.ejs
    <%- include ../partials/header %>
      <a href="/posts/add" class="btn btn-md btn-primary">Add post</a>
      <h1>Posts Index Pages</h1>
      <h3>Here are the Following posts</h3>
      <% posts.forEach(function(post){ %>
          <h2><%= post.title %></h2>
          <p><%= post.body %></p>
          <a href="/posts/<%= post._id%>">Show</a>
          <a href="/posts/edit/<%= post._id%>">Edit</a>
          <a href="#" class="deletePost" data-id="<%= post._id%>">Delete</a>
      <% }) %>
    <%- include ../partials/footer %>
    
    
    // add.ejs , update.ejs
      <%- include ../partials/header %>
        <a href="/posts" class="btn btn-lg btn-default">Back To Index</a>
        <h1>Add Post</h1>
        <form method='POST', action='/posts/add'>
        <div id="form-group">
          <label>Title</label>
          <input name='title' type="text" class="form-control">
        </div>
        <div id="form-group">
          <label>Body</label>
          <input name='body' type="text" class="form-control">
        </div>
        <br>
        <input value='Submit' type="Submit" class="btn btn-primary">
        </form>
      <%- include ../partials/footer %>
    
  7. Delete 我要拿出來講,因為做法不一樣, 我們這裡用AJAX 的方式, 然後有成功的話就會回來 /posts. main.js

    $(document).ready(function(){
      $('.deletePost').on('click', deletePost);
    });
    function deletePost(){
      var confirmation = confirm('Are you sure?')
      if(confirmation){
        $.ajax({
          type: 'DELETE',
          url: '/posts/delete/' + $(this).data('id')
        }).done(function(response){
          window.location.replace('/posts')
        })
        window.location.replace('/posts')
      } else {
        return false;
      }
    }
    

總結

以上就是我們如何用express做CRUD, 我這裡帶過整個code, 我知道很多基本的觀念我沒有講解. 如果要寫可能寫不完. 如果看不懂, 可以參考我的github repo. express-blog

參考文件


上一篇
[Day 15] Redux Dev Tool, debug redux 的好工具
下一篇
[Day 17] Node 串金流, 不然怎麼跟客戶收錢 Part I
系列文
如何成為工程師? (從工地到前端工程師)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言