koa mysql mongodb_Koa+mongodb实战

本文介绍了一个结合Koa和MongoDB的脚手架项目,包括目录结构、基本配置、路由设置、参数处理、数据库操作等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

koa 脚手架

本人弄了一个koa脚手架,koa和mongodb组合而成, 已上传GitHub. 👏 👏 👏 👏

cc9cd0173cfb131f8385e0d24a932b31.png

目录结构如上,一个控制器(也就是写代码的地方),一个日志,一个数据库模型,一个路由,一个工具,和入口文件。

写代码只要添加路由 填充控制器就好了,如图所示

d34b60cfb8b7995f15f3a990379d0c2f.png

31b6e819e568cc61f9bbbe813468575b.png

下面解析下有哪些构成的👇

koa

const Koa = require('koa');

const app = new Koa();

// response

app.use(ctx => {

ctx.body = 'Hello Koa';

});

app.listen(3000);

复制代码

router

官方例子

var Koa = require('koa');

var Router = require('koa-router');

var app = new Koa();

var router = new Router();

router.get('/', (ctx, next) => {

// ctx.router available

});

app

.use(router.routes())

.use(router.allowedMethods());

复制代码

实战例子

// routers/index.js

const Router = require('koa-router')

const Controllers = require('./controller')({})

const dateNumberController = Controllers('date_number')

const router = new Router({

prefix: '/api'

})

router

.post(dateNumberController.getPath('add'), dateNumberController.add)

.get(dateNumberController.getPath(`select`), dateNumberController.find)

.post(dateNumberController.getPath(`remove`), dateNumberController.delect)

.post(dateNumberController.getPath(`update`), dateNumberController.update)

module.exports = router

// routers/controller.js

const controllerFunction = ({basePath = '../controllers/', router_path_function}) => (controllerName) => {

const divController = require([basePath, controllerName].join(''))

const prefix = controllerName

class Controller extends divController {

prefix = ''

getPath(name){

return router_path_function ? router_path_function(this.prefix, name) : `/${this.prefix}/${name}`

}

}

const controller = new Controller()

controller.prefix = prefix

return controller

}

module.exports = controllerFunction

// controllers/date_number.js

见下面的 mongodb 里面的模型代码

// main.js

const router = require('./routers')

app.use(router.routes());

复制代码

bodyparser

有了路由,但是我们还需要前端传递过来的参数,所以需要先获取参数

例子

app.use(async ctx => {

ctx.body = ctx.request.body;

});

复制代码

这时候post请求就可以解析了,不管是application/json还是application/x-www-form-urlencoded

效果

3d6038169c42f0290b90d4d0e2c9671c.png

koa-parameter

拿到参数后我们需要校验它

// main.js

const parameter = require("koa-parameter")

const error = require("koa-json-error")

app.use(parameter(app));

// 这个是json错误处理,可以自动抛出http status 422

app.use(

error({ postFormat: (e, { stack, ...rest }) => ({ stack, rest }) })

)

// ctx里面,比如路由里面

ctx.verifyParams({

date: { type: "string", required: true },

list: { type: "array", required: true },

})

复制代码

mongodb

拿到参数,我们下一步就是需要操作数据了

基础

初始化

安装mongodb,然后npm安装mongoose, 如下初始化即可

const mongoose = require('mongoose')

// db是数据库名称哦,没有的话会自动创建

const DB_ADDRESS = "mongodb://localhost:27017/db"

mongoose.connect(DB_ADDRESS, {useNewUrlParser: true, useUnifiedTopology: true}, err => {

if (err) {

log.fatal({msg: '[Mongoose] database connect failed!', err})

} else {

console.log('[Mongoose] database connect success!')

}

})

module.exports = mongoose

复制代码

建立模型

使用的时候,我们需要先建立集合(在mysql里面叫表),但是MD更灵活,可以直接在代码里面操作,我们先建立模型。

const mongoose = require('mongoose');

const { Schema, model } = mongoose;

// 数据模型

let DateNumberSchema = new Schema({

date: { type: String, required: true, unique: true },

list: { type: Array, require: true },

});

module.exports = model('DateNumber', DateNumberSchema);

复制代码

操作数据库

const data = await DateNumber.find()

复制代码

新增

// 要和模型对应

const data = await to( new DateNumber({date, list}).save()

复制代码

const data = await DateNumber.deleteOne({date: date})

复制代码

const data = await DateNumber.updateOne({date}, {$set: {list}})

复制代码

例子

const DateNumber = require('../models/dateNumber')

class DateNumberController {

prefix = ''

getPath(name){

return `/${this.prefix}/${name}`

}

async add(ctx, next){

ctx.verifyParams({

date: { type: "string", required: true },

list: { type: "array", required: true },

})

const {date, list} = ctx.request.body

const [err, data] = await to( new DateNumber({date, list}).save() )

if(err) return ctx.throw(500, err)

ctx.response.body = data

}

async find(ctx, next){

const data = await DateNumber.find()

ctx.response.body = data.join('\n')

log.info('find')

}

async delect (ctx, next){

ctx.verifyParams({

date: { type: "string", required: true },

})

const {date} = ctx.request.body

const data = await DateNumber.deleteOne({date: date})

ctx.response.body = data

}

async update(ctx, next){

ctx.verifyParams({

date: { type: "string", required: true },

list: { type: "array", required: true },

})

const {date, list} = ctx.request.body

const [err, data] = await to( DateNumber.updateOne({date}, {$set: {list}}) )

if(err) return ctx.throw(500, err)

ctx.response.body = data

}

}

module.exports = new DateNumberController()

复制代码

对应关系(来自菜鸟教程)

SQL术语/概念

MongoDB术语/概念

解释/说明

database

database

数据库

table

collection

数据库表/集合

row

document

数据记录行/文档

column

field

数据字段/域

index

index

索引

table

joins

表连接,MongoDB不支持

primary

key

primary key主键,MongoDB自动将_id字段设置为主键

MAC的需要先运行mongod,然后再开一个窗口,不然会提醒找不到服务;

Windows有自带的可视化软件,安装的时候install mongoDB compass勾上即可

to function

上面有一个代码用到了to

to是对promise的一个封装,变成[err, data] 这种形式,这样有一个好处是不需要写try catch,又可以平级处理错误。

to是全局的,在main.js引入

进阶

分页查询

new DateNumber.find().skip(条数*(页码-1)).limit(条数)

复制代码没有设置索引的话会很慢

连左集合查询

db.orders.aggregate([

{

$lookup:

{

from: "inventory",

localField: "item",

foreignField: "sku",

as: "inventory_docs"

}

}

])

复制代码

日志

使用log4js实现日志

使用方式

var log4js = require('log4js');

var logger = log4js.getLogger();

logger.level = 'debug';

logger.debug("Some debug messages");

复制代码

Level

等级作用是,输出>=当前级别的日志bdf876334c9471b579b9f38d2332462c.png

输出设置

我设置的是,info正常输出,输出的时候按日期分(这样文件不会太大),如果遇到error这种大问题就发邮件,例子如下,包含测试代码,你配置下email里面的账号密码就可以运行了

const config = {

// 例子

email: {

host: 'smtp.qq.com',

auth: {

user: '你的qq号@qq.com',

pass: '你的密码,',

},

recipients: '发送方@126.com'

}

}

const LOGINFO = {

appenders: {

info: {

type: "DateFile",

category: 'dateFileLog',

filename: path.join(__dirname, './log/info/'),

pattern: "yyyy-MM-dd.log",

alwaysIncludePattern: true

},

email: {

type: '@log4js-node/smtp',

//发送邮件的邮箱

sender: config.email.auth.user,

//标题

subject: 'Latest error report',

SMTP: {

host: config.email.host,

auth: config.email.auth,

},

recipients: config.email.recipients

}

},

}

const log4js = require('log4js')

log4js.configure(LOGINFO)

const log_info = log4js.getLogger()

const log_error = log4js.getLogger('error')

global.log = {

debug: log_info.debug.bind(log_info),

info: log_info.info.bind(log_info),

warn: log_info.warn.bind(log_info),

error: log_error.error.bind(log_error),

fatal: log_error.fatal.bind(log_error),

}

// 这个是测试代码

setTimeout(() => {

log.fatal({

msg: '测试',

err: 'fatal'

})

}, 400)

复制代码邮箱密钥获取方式: 进入qq邮箱,设置----> 账户 ------->开启服务:POP3/SMTP服务 ----->生成授权码log.fatal({

msg: '测试',

err: 'fatal'

})

复制代码

效果2a903213875e93a41a822e685574016e.png

d604991bc82e5a1919475efbffe47d91.png

其他

各位大哥哥小姐姐麻烦点个赞,我要冲3级,谢谢

-- 完 --

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值