# 适合初学者的koa2+mongodb初体验

> 一个老前端第一次写 node 服务的全过程记录。koa2 的洋葱中间件怎么理解、mongodb 的基本 CRUD 怎么写、再到把它们串成一个最小可用的 API。文末附 demo 仓库，跟着 README 跑一遍就能上手。

- URL: https://tenggouwa.com/posts/koa2-mongodb/
- 发布: 2019-06-27
- 标签: 后端, node, KOA, mongodb

## 前言
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;笔者的前端开发已经有些时日了，对于node一直保留着最初的恐惧，倘若一座不可跨越的高山，思前想后终于迈出最后一步，踏入了开拓自己视野的新视界，希望在看这篇文章的你可以一起跟我动手尝试。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果你是个急性子，我就提供一波传送门 github:https://github.com/tenggouwa/koa2-mongodb<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;你可以先star,再拉代码，慢慢的看这篇文章。

## KOA
>next generation web framework for node.js

**面向node.js的下一代web框架。** <br />
由Express团队打造，特点：优雅、简洁、灵活、体积小。几乎所有功能都需要通过中间件实现。

## 环境搭建
 + node
   + node官方下载地址: https://nodejs.org/zh-cn/download/
 + mongodb
   + mac下mongodb安装教程: https://www.jianshu.com/p/7241f7c83f4a
   + windows下mongodb安装教程: https://blog.csdn.net/zhongkaigood/article/details/81475904
   + robomongo(mongodb数据库可视化--免费): https://robomongo.org/download
 + 本地安装nodemon
   + nodemon会监听你的代码，当有变动的时候自动帮你重启项目(好东西)
   + npm: https://www.npmjs.com/package/nodemon
 + yarn(选装)---代替npm/cnpm
 + homebrew(选装)---包版本管理工具

## Hello World!!!
+ 创建目录
    + `mkdir node-app && cd node-app`
    +  `npm init`
    +  `yarn add koa -S`
    +  `touch app.js`
+  在编辑器中打开app.js并输入以下代码
    ```
    const Koa = require('koa');
    const app = new Koa();
    app.use(async ctx => {
        // ctx.body 即服务端响应的数据
        await ctx.body = 'Hello world!!!';
    })
    // 监听端口、启动程序
    app.listen(3000, err => {
        if (err) throw err;
        console.log('runing at 3000');
    })
    ```
+ 启动app.js
    + `node app` 或 `nodemon app`
+ 本地访问localhost:3000
+ **got it!!!!**

## KoaRouter

+ 安装koa-router
    + `yarn add koa-router -S`
+ 在app.js中添加如下代码
    ```
    const router = require('./router')
    router(app)
    ```
+ koa-app目录下新建controller文件，controller下新建home.js
+ koa-app目录下新建router.js 并输入以下代码controller文件，
    ```
    const router = require('koa-router')()
    module.exports = (app) => {
      router.get( '/index', app.controller.home.index )
    }
    ```
+ home.js输入以下代码
    ```
    module.exports = {
        index: async(ctx, next) => {
            console.log(ctx) // 输出ctx 以查看内容
            ctx.response.body = '<h1>HOME page index</h1>'
        },
    }
    ```
+ 运行代码 `node app` 或 `nodemon app`
+ 本地访问localhost:3000/index
+  **got it!!!!** 

## 处理post
+ koa-bodyparser
+ 安装koa-bodyparser
    + `yarn add koa-bodyparser -S`
+ router.js添加代码
    + `router.post( '/post', bodyParser(), app.controller.home.post ) // 重点在'post'后面的bodyParser()`
+ home.js添加代码
    ```
    post: async(ctx, next) => {
        console.log(ctx.request.body) // 输出ctx 以查看内容
    },
    ```
+ 使用postman创建post请求，访问localhost:3000/post, 并传递参数，看终端返回内容
+ **got it!!!**

## 处理跨域
+ koa2-cors安装
    + `yarn add koa2-cors -S`
+ 在app.js内添加如下代码
    ```
    const cors = require('koa2-cors')
    .......
    // 其他代码
    app.use(cors())
    ```
****
>至此，我们就拥有了一套简单的koa项目，可以进行前后台交互，或者mock数据搭建
****

## mongodb
+ 在环境搭建中可以看到安装mongodb以及数据库可视化的方法
+ 在项目中`yarn add mongoose -S`
+ 创建models文件夹并在app.js添加如下代码
```
const mongoose = require('mongoose')
const path = require('path')
const fs = require('fs')

// 链接数据库一定放在koa前面
mongoose.Promise = require('bluebird')
mongoose.connect('mongodb://127.0.0.1/tenggouwa',{useNewUrlParser: true})
// 获取数据库表对应的js对象所在的路径
const models_path = path.join(__dirname, './models')
// 已递归的形式，读取models文件夹下的js模型文件，并require
var walk = function(modelPath) {
  fs
    .readdirSync(modelPath)
    .forEach(function(file) {
      var filePath = path.join(modelPath, '/' + file)
      var stat = fs.statSync(filePath)
      if (stat.isFile()) {
        if (/(.*)\.(js|coffee)/.test(file)) {
          require(filePath)
        }
      } else if (stat.isDirectory()) {
        walk(filePath)
      }
    })
}

walk(models_path)
```
+ 这一步可以将项目与mongodb链接
+ 在models里创建block.js并加入如下代码
```
'use strict'
var mongoose = require('mongoose')
var Schema = mongoose.Schema;
/**
 * 定义一个模式(相当于传统意义的表结构)
 * 每个模式映射mongoDB的一个集合，
 * 它定义（只是定义，不是实现）这个集合里面文档的结构，就是定义这个文档有什么字段，字段类型是什么，字段默认值是什么等。
 * 除了定义结构外，还定义文档的实例方法，静态模型方法，复合索引，中间件等
 * @type {mongoose}
 */
var BlockSchema = new Schema({
  peers: String,
  blocks: String,
  createAt: {
    type: Date,
    default: Date.now()
  },
  updateAt: {
    type: Date,
    dafault: Date.now()
  }
})
/**
 * 定义模型
 * 模型用来实现我们定义的模式，调用mongoose.model来编译Schema得到Model
 * @type {[type]}
 */
// 参数User 数据库中的集合名称, 不存在会创建.
// console.log(BlockSchema)
var Block = mongoose.model('Block', BlockSchema)
module.exports = Block
```
+ 这一步是为了添加传统意义上的表结构，并放到Block表里面
+ 接下来我们就可以在controller里面去操纵mongodb，进行业务操作了。例如：
    ```
    delBlock: async(ctx, next) => {
        const params = ctx.request.body // 拿到返回的参数
        const result = await Block.where({ // 通过id去Block里面查找对应数据
          _id: params.id
        }).remove() // 将该条数据删除
      },
    ```
+ **got it!!!**
    
## mongodb常用操作
+ 保存数据
  + `save()`
+ 查取数据
  + 查询 `find()`   `finOne()`
  + `where()`
+ 更改数据
  + `where().update()`
+ 删除数据
  + `where().remove()`
+ 排序
  + `find().sort()`
+ 分页
  + `find().sort().skip(页码).limit(单页数据)`
+ **got it!!!**

## Just Do It

## 写在最后
当你看完这篇文章，你已经明白基本的koa+mongdb的用法了，希望你可以通过学习node以及其生态，提升自己的知识储备
跟笔者一起加油！
