zoukankan      html  css  js  c++  java
  • koa mogoose 创建后台服务连接数据库并进行增删改查

    本文原创 ,转载请标明出处

    1 koa的基本使用

    koa是基于node平台的web开发框架

    使用koa去创建一个服务器

    const Koa = require('koa')
    // bodyParser 处理post请求
    const bodyParser = require('koa-bodyparser')
    const port = 7001
    const app = new Koa()
    
    app.use(bodyParser())
    app.use(async ctx => {
      ctx.body = 'hello , i am first koa applicance'
    })
    
    app.listen(port)
    

    koa 使用 下面方式 利用ctx.body将内容或接口数据返回给到页面,若作为接口时,未写ctx.body接口将报错404 Not Found

    app.use(async ctx => {
      ctx.body = ''
    })
    

    下面一个从后台获取数据返回给到页面 的demo(作为中间层)

    const Koa = require('koa')
    // bodyParser 处理post请求
    const bodyParser = require('koa-bodyparser')
    // 用于请求后台数据 当我们想把改服务作为web和后台的中间层时 需要使用request-promise 或者request 当然还有其他的
    const request = require('request-promise')
    const port = 7001
    const app = new Koa()
    
    app.use(bodyParser())
    
    // 向后台发起请求
    let _callApi = (url, datas, headers) => {
      // 本文以POST请求为例说明,其他方式请参阅request-promise官方文档
      let options = {
        uri: url,
        method: 'POST',
        body: datas,
        json: true,
        timeout: 10000
      }
      if (headers) {
        options.headers = headers
      }
      return new Promise((resolve, reject) => {
        request(options)
          .then(res => {
            resolve(res)
          })
          .catch(err => {
            reject(err)
          })
      })
    }
    
    app.use(async ctx => {
      ctx.body = 'hello , i am first koa applicance'
    })
    
    app.use(async ctx => {
      let queryUrl = ctx.request.url.split('?')[0]
      if (queryUrl === '/mytest/testpost') {
        let data = ctx.request.body
        let response = await _callApi('apiUrl', data)
        ctx.body = response
      }
    })
    app.listen(port)
    

    使用 ctx.request 将web端请求的内容拿到,根据自己的需求组装 将内容发送给后台获取接口数据 可以自行打印ctx.request

    注意:A 当在项目中使用session时 需要有配置文件并且给app设置keys 

    // 存储 内容
    const CONFIG = {
      overwrite: false,
      maxAge: 7200000 //过期时间设置两个小时
    }
    app.keys = ['myvars is changing']
    app.use(session(CONFIG, app))
    
    // 在接口中存数据
    ctx.session.username = 'myName'
    // 在接口中去数据
    let userName =  ctx.session.username
    

        B:项目中使用cookies

    const Koa = require('koa');
    const app = new Koa();
    
    app.use(async ctx=>{
        if(ctx.url === '/public'){
            ctx.cookies.set(
                'name', 'public', {
                    domain: 'localhost',
                    path: '/public',
                    // 有效时长 表示从Date.now()得到的毫秒值
                    maxAge: 24 * 60 * 60 * 1000,
                    // cookies 过期的date
                    expires: new Date('2018-12-31'),
                    // 服务器可访问cookie 默认true
                    httpOnly: false,
                    // 是否覆盖以前设置的同名的cookie默认false 
                    overwrite: false
                }
            );
            ctx.body = 'cookie success';
        }else{
            ctx.body = 'no cookie';
        }
    });
    
    app.listen(3000, () => {
        console.log('服务开启成功在3000端口');
    });

    当然 当我们接口很多时 可以使用koa-router进行路由的定义 ,koa-router支持很多接口方式

      router.get('/users', ctx => {
        // ....
      })
      router.post('/users', ctx => {
        // ....
      })
      .put('/user/:id', ctx => {
        // ....
      })
      .del('/user/:id', ctx => {
        // ....
      })
      .all('/user/:id', ctx => {
        // ....
      });
    

    koa-router 引入方式:

    const Router = require('koa-router')
    const router = new Router()
    //或者下面的方式
    const router = require('koa-router')()
    // router装载 routes代表可能多个
    app.use(router.routes());
    // 如get 就只能用get进行请求 使用post将会报错405 Method Not Allowed;
    app.use(router.allowedMethods());
    

      

    2 mongodb 的基本用法

    mongodb的安装请参见菜鸟教程:https://www.runoob.com/mongodb/mongodb-window-install.html 或者参见其他

    (安装教程不同的是现有的 安装包下载完直接默认了 data和log的存放地址 可以自定义修改), 安装完成可以通过mongod 命令查看

      开始使用:命令行输入 mongo 之后就可以进行增删改查;

     也可以在当前bash目录下写js文件 去连接数据库进行增删改查;执行命令 load(‘文件名’),比如dboper.js:

    var userName = "testtwo";
    var time = Date.parse(new Date());
    var data = {
        "title": userName,
        "registTime": time
    };
    var db = connect('testtwo');
    db.testtwo.insert(data);
    print('insert success');
    命令行输入load('dboper.js')  ,当控制台打印 insert success 即运行成功
     
      A.数据库
           创建 : use myDbone(数据库没有,将被创建,但是show dbs时不显示,因为是空的,需要插入内容才可以)
           查看: db (看当前使用的所在的数据库)或 show dbs(看所有数据库)
           删除:db.dropDatabase(),删除当前数据库,演示如下:
    use testone
    switched to db testone
    db
    testone
    db.dropDatabase()
    { "dropped" : "testone", "ok" : 1 }

      B 集合 (相当于mysql的表格)
          创建集合:db.createCollection(name, options) options可选 指定内存的大小索引等 详细信息见官网或菜鸟教程
          查询集合:show tables 或 show collections
          删除集合: db.myColl.drop()

      C 文档 (相当于mysql的行)
          插入文档:db.myColl.insert({title:‘myFirst’,url:'www.baidu.com'}或者变量名)
     
          查找文档:db.myColl.find()   //查找所有
                          db.myColl.findOne()   //查找第一条数据
                          db.myColl.find({title:‘myFirst’})   //条件查询
                          db.myColl.find().limit()  // 限制访问的数量
                          db.myColl.find().skip()  // 跳过多少去访问 用limit和skip可以实现分页的效果
                          db.myColl.find().sort({age:1})   //1 按age升序排列, -1 按降序排列
          
    //数据查询find
    $gte: 大于等于
    $lte: 小于等于
      db.user.find(
        // 查询条件
        {age: {$gte: 20, $lte: 30}},
        // 显示的字段名称
        {name: true, age: true, _id: false}
      )
    
    $in: 数组内等于20和等于25
      db.user.find(
        {age: { $in: [20, 25]}}, //等于20 和25的
        {name: true, age: true, _id: false}
      )
    
    $or $and 
      db.user.find({
        $and/$or: [
            {age: { $gte: 20}},
            {'pc.brand': 'IBM'}
        ]},
        {name: true, age: true, _id: false}
      )
      db.user.find(
        // hobby中包含篮球
        {hobby: '篮球'},
        // hobby只是篮球,
        // {hobby: ['篮球']},
        {name: true, age: true, _id: false}
      );
    
    $all 如下既喜欢篮球又喜欢敲代码 若为$in则是或的关系
      db.user.find(
        {hobby: {$all: ['篮球', '敲代码']}},
        {name: true, age: true, _id: false}
      );
    
    $size 按照数组的长度去查询
      db.user.find(
        {hobby: {$size: 3}},
        {name: true, age: true, _id: false}
      );
    
    limit 每次查询多少条
    skip 跳过多少条
    sort 按那个字段进行排序 1和-1
      db.user.find(
        {},
        {name: true, age: true, _id: false}
      ).limit(1).skip(1).sort({age: -1})
     
          更新文档:db.myColl.update({title:myFirst},{$set:{title:'myFirltUpdate'}}) 按条件查找内容并进行替换
                          db.myColl.updateOne({})
    数据更新
    $set 修改指定的可以值
      db.myColl.update({ name:'lxh' },{ $set:{ 'age':18 }})
    $unset 删除一个keyvalue值 name=lxh这条数据里面将没有age这个key和value值
      db.myColl.update({ name:'lxh' },{ $unset:{ 'age': ''}})
    upsert(更新插入) 比如下面有age值就去更新,没有就去插入这个值
      db.myColl.update({ name:'lxh' },{ $set:{ age:18 }},{upsert:ture})
    multi 所有文档都加上hobby属性,multi:false只有第一条数据会加
      db.myColl.update({},{$set:{hobby:['code']}},{multi:true})
    $push 给文档里面的某个属性push内容,需要时数组格式
      db.myColl.update({name:'lxh'},{$push:{hobby:'chiji'}})
    $addToSet  查找内容是否已存在,存在了就不加,不存在就push
      db.myColl.update({name:'lxh'},{$addToSet:{hobby:'sleep'}})
    $each 
      db.myColl.update({name:'lxh'},{$addToSet:{hobby:{$each:['sleep','wake up']}}})
    $set
      db.myColl.update({name:'lxh'},{$set:{'hobby.0':'sport'}})
    findAndModify 查找并且修改(上面不会返回任何内容,该方法应答式的)
      var modify = {
        findAndModify: 'user',  //应答式的,会返回操作结果
        query: {name: 'lxh'},
        update: {$set: {age: 22}},
        new: true //true 更新后的结果,false更新前的结果
      };
         
            删除文档:db.myColl.remove({title:myFirstUpdate}) 删除查找到的内容
                          db.myColl.remove({}) 删除所有文档
          db.myColl.drop() //删除所有内容(整个集合)
     
            数据库的索引:
                生成随机索引(需要频繁查询时需要建立索引加快查询速度,但是同时会增加磁盘的消耗,在写入和更新数据时会一定程度的降低写入想能)
                   db.myColl.ensureIndex({username:1})
                查询索引
                   db.myColl.getIndexes()  
                删除当前索引
                   db.myColl.dropIndex({username:1})

    3 koa 连接mongodb 进行连接数据库并增删改查,mongoose是Node和MongoDB数据通讯的数据建模库

    npm install mongoose --save

      A  使用mongoose.connect连接数据库 

    const mongoose = require('mongoose')
    //testone 是自己建的db
    const DB_URL = 'mongodb://127.0.0.1:27017/testone'
    
    mongoose.connect(DB_URL, {
      useNewUrlParser: true,
      useUnifiedTopology: true
    })
    var db = mongoose.connection
    db.on('connected', function() {
      console.log('Mongoose connection open to ' + DB_URL)
    })
    
    // 连接异常数据库报错
    db.on('error', function(err) {
      console.log('Mongoose connection error:' + err)
    })
    
    // 连接断开 disconnected 连接异常断开
    db.on('disconnected', function() {
      console.log('Mongoose connection disconnected')
    })
    
    module.exports = mongoose
    

      注意:连接数据库时 不设置 useNewUrlParser: true,useUnifiedTopology: true 会导致报错 过时的 告诉你需要通过设置这个 来进行兼容

      B 使用mongoose.Schema 去创建数据表里面的各个字段和类型,每个mongoose都是从Schema开始,映射到MongoDB集合

    const Schema = mongoose.Schema
    
    const testSchema = new Schema({
      name: String,
      age: Number,
      studentId: { type: String, unique: true }  //设置了unique 为true新建时传入重复的值会提示E11000 duplicate key error collection***
    })
    

      C 使用Model  将Schema 和底层MongoDB数据库连接到一起,model的实例就是文档,model负责从底层MongoDB数据库创建和读取文档

    const Student = mongoose.model('testone', testSchema)
    

     D 创建自己的类 封装增删改查功能

    class StudentDb {
      constructor() {}
      // 查询
      query(obj) {
        return new Promise((resolve, reject) => {
          Student.find({}, (err, res) => {
            // Student.find({ age: { $gte: 22, $lt: 25 } }, (err, res) => {   //按条件去查询
            if (err) {
              reject(err)
            }
            resolve(res)
          })
            .limit(obj.pageSize) // 限制访问的数量
            .skip(obj.pageSize * (obj.pageNum - 1)) // 跳过多少去访问 用此可以实现分页的效果
            .sort({ age: 1 }) //1 按age升序排列, -1 按降序排列
        })
      }
      // 保存
      save(obj) {
        const m = new Student(obj)
        return new Promise((resolve, reject) => {
          m.save((err, res) => {
            if (err) {
              reject(err)
            }
            resolve(res)
            console.log(res)
          })
        })
      }
      // 按studentId查询
      where(obj) {
        const query = JSON.parse(JSON.stringify(obj))
        return new Promise((resolve, reject) => {
          Student.find({ studentId: query.studentId }, (err, res) => {
            if (err) {
              reject(err)
            }
            resolve(res)
          })
        })
      }
      // 更新
      update(obj) {
        const query = JSON.parse(JSON.stringify(obj))
        return new Promise((resolve, reject) => {
          Student.updateOne({ _id: query._id }, { $set: query }, (err, res) => {
            if (err) {
              reject(err)
            }
            resolve(res)
            console.log('update=====', res)
          })
        })
      }
      // 删除
      del(obj) {
        const query = JSON.parse(JSON.stringify(obj))
        return new Promise((resolve, reject) => {
          Student.remove({ studentId: query.studentId }, (err, res) => {
            if (err) {
              reject(err)
            }
            resolve(res)
            console.log(res)
          })
        })
      }
    }
    

      E 导出这个类在其他的地方使用

    module.exports = new StudentDb()
    

     F 在需要的文件中引入 并使用

    const StudentDb = require('./index')   //上面类定义的文件
    

     G 利用koa-router 以及上面封装的方法进行数据库的操作

    // 查询所有内容接口
    router.get('/testMogodb/query', async ctx => {
      // const queryPars = ctx.request.body
      const queryPars = {
        pageSize: ctx.request.body.pageSize,
        pageNum: ctx.request.body.pageNum
      }
      let data = await StudentDb.query(queryPars)
      ctx.body = data
    })
    // 按条件查询接口
    router.post('/testMogodb/search', async ctx => {
      const queryPars = ctx.request.body
      console.log('queryPars', queryPars)
      let data = await StudentDb.where(queryPars)
      ctx.body = data
    })
    // 添加接口
    router.post('/testMogodb/add', async ctx => {
      const studentObj = {
        name: ctx.request.body.name,
        age: ctx.request.body.age,
        studentId: ctx.request.body.studentId
      }
      let code, message
      try {
        await StudentDb.save(studentObj)
        code = 0
        message = 'Add successful'
      } catch (error) {
        code = -1
        message = error || 'Add failure'
      }
      ctx.body = {
        code,
        message
      }
    })
    // 更新已有内容的接口
    router.post('/testMogodb/update', async ctx => {
      let code, message
      const result = await StudentDb.update({
        name: ctx.request.body.name,
        age: ctx.request.body.age,
        studentId: ctx.request.body.studentId,
        _id: ctx.request.body._id
      })
      try {
        await result
        code = 0
        message = 'Update successful'
      } catch (error) {
        code = -1
        message = error || 'Update failure'
      }
      ctx.body = {
        code,
        message
      }
    })
    // 删除指定内容接口
    router.post('/testMogodb/del', async ctx => {
      const studentObj = {
        // _id: ctx.request.body._id
        studentId: ctx.request.body.studentId
      }
      let code, message
      try {
        await StudentDb.del(studentObj)
        code = 0
        message = 'Delete successful'
      } catch (error) {
        code = -1
        message = error || 'Delete failure'
      }
      ctx.body = {
        code,
        message
      }
    })  

     注意 上面router使用过程中 async await 语法的使用;

    详细代码地址:https://github.com/liangxianh/koa-mongoose.git 

    参考地址:官方文档https://mongoosejs.com/docs/index.html

  • 相关阅读:
    beta冲刺————第二天(2/5)
    beta冲刺————第一天(1/5)
    个人作业——软件产品案例分析
    c++第七次作业____最后的总结
    计算器图形界面
    object-oriented second work
    第五次作业(文件处理)
    object-oriented first work
    第四次作业--计算器简单计算
    新的Calculator的规范作业
  • 原文地址:https://www.cnblogs.com/xhliang/p/11913119.html
Copyright © 2011-2022 走看看