// https://mongoose.shujuwajue.com/guide/schemas.html 中文文档
// 1. 启动数据库 默认 c:\data\db mongod
// mongod --dbpath=D:\Data\mongodb\_data 设置数据库目录
// 2. PS D:\mv> cnpm i -S mongoose 安装
const mongoose = require('mongoose')
// console.log(mongoose)
// 3. 连接数据库
// let db_company = mongoose.connect('mongodb://workers:workers@127.0.0.1:27017/company?authSource=admin') options这块没懂
let db_company = mongoose.connect('mongodb://workers:workers@127.0.0.1:27017/company') //company 的库
// let db_company = mongoose.connect('mongodb://127.0.0.1:27017/company') 不使用账户密码登录
// 数据库连接失败:
mongoose.connection.on('error', err => {
console.log('company:', err)
})
// 数据库连接成功:
mongoose.connection.on('open', () => {
console.log('company:success')
})
//增加数据库监听事件
mongoose.connection.on('disconnected', () => {
console.log('***********数据库断开***********')
})
// 数据库模型 schema
/*
Schema:一种以文件形式存储的数据库模型骨架,无法直接通往数据库端,
也就是说它不具备对数据库的操作能力,仅仅只是数据库模型在程序片段中的一种表现,
可以说是数据属性模型(传统意义的表结构),又或着是"集合"的模型骨架。
*/
// 建立集合 wokers 的 schema
// 特别类型 var ObjectId = mongoose.Schema.Types.ObjectId;
// new Schema({..}, { versionKey: '_somethingElse' }) 默认会有_v 可以修改
const wokersSchema = new mongoose.Schema({
name: { type: String },
interest: { type: Array },
age: { type: Number, default: 18 },
idNum: { type: String, default: 'idofe' + String(Math.random()).substring(0, 6) },
contentinfo: { type: String, default: 'no msg' },
schematext: { type: Number, default: 1 }
})
// 建立集合 实例 model 参数1 集合名称 参数2 schema
const wokersModel = mongoose.model('wokers', wokersSchema)
// 插入数据
// wokersModel.create({name:'wangrong2',age:54},(err,doc)=>{
// if(err){
// console.log('插入数据错误:',err)
// }else{
// console.log('结果数据:',doc)
// }
// })
// model查询
// setTimeout(() => {
// wokersModel.find({},{name:true,age:true,idNum:true}, (err, docs) => {
// if (err) {
// console.log('err:find', err)
// } else {
// console.log(docs)
// }
// })
// }, 2000);
// 建立 服务器 测试
// 服务
const koa = require('koa')
// 路由
const koaRouter = require('koa-router')
// 数据body
// const bodyParser = require('koa-better-body')
// console.log(this.request.body) // if buffer or text
// console.log(this.request.files) // if multipart or urlencoded
// console.log(this.request.fields) // if json
const bodyParser = require('koa-bodyparser') //
// const bodyParser = require('koa-body')
// 跨域
const cors = require('koa-cors')
const app = new koa()
const router = new koaRouter()
const wokersRouter = new koaRouter()
Object.isEmptyObject = (e) => {
for (let t in e)
return !1;
return !0
}
//wokers 模块
wokersRouter
.get('/', async (ctx, next) => {
// 获取所有工作人员 查询
let queryObj = ctx.request.query
let q = {}
if (queryObj.name) {
q.name = queryObj.name
}
if (queryObj.idNum) {
q.idNum = queryObj.idNum
}
/*
说明:我们只需要把显示的属性设置为大于零的数就可以,当然1是最好理解的,
_id是默认返回,如果不要显示加上("_id":0),但是,
对其他不需要显示的属性且不是_id,如果设置为0的话将会抛异常或查询无果
find过滤查询 :find查询时我们可以过滤返回结果所显示的属性个数。
findOne查询 :只返回符合条件的首条文档数据。
findById查询:根据文档_id来查询文档。
*/
// await wokersModel.find(q, { schematext: false,name:true }) 报下面的错误
await wokersModel.find(q, { schematext: false })//正常 有false 不能有true 除非 false是 _id
.then(docs => {
ctx.body = { success: true, msg: 'ok', data: docs }
}).catch(err => {
/*
"data":{
"name":"MongoError",
"message":"Projection cannot have a mix of inclusion and exclusion.",
"ok":0,
"errmsg":"Projection cannot have a mix of inclusion and exclusion.",
"code":2,
"codeName":"BadValue"
}
*/
ctx.body = { success: false, msg: 'no', data: {err,queryObj} }
})
await next()
})
.get('/age', async (ctx, next) => {
// 获取所有年龄 排序 查找 分页
let queryObj = ctx.request.query
let q = {}//查找条件
let qo = {}//处理条件
let maxPage=null//总页面
let pageNow=null//当前页面
let totalCount=null//总数
//参数判断
if(Object.isEmptyObject(queryObj)){
ctx.status = 400
ctx.body = { success: false, msg: 'no' }
return
}
q.age={$exists:true}
// 最小年龄限制
if(queryObj.minAge){
q.age.$gte=Number(queryObj.minAge)
}
// 最大年龄限制
if(queryObj.maxAge){
q.age.$lte=Number(queryObj.maxAge)
}
//获取总页数 年龄存在
await wokersModel.count(q)
.then(count=>{
totalCount=count
if(count==0){
ctx.body = { success: false, msg: 'no res', data: {count,queryObj} }
}
maxPage=Math.ceil(count/2)
})
.catch(err=>{
ctx.body = { success: false, msg: 'no', data: {err,queryObj} }
})
// 分页
if (queryObj.page) {
if(queryObj.page>maxPage){
pageNow=maxPage
qo.skip=(maxPage-1)*2
} else{
pageNow=Number(queryObj.page)
qo.skip=(Number(queryObj.page)-1)*2
qo.limit=2
}
}else{
pageNow=1
qo.skip=0
qo.limit=2
}
// 排序
if (queryObj.sort) {
qo.sort={age:Number(queryObj.sort)}
}else{
qo.sort={age:1}
}
// 查找 参数1 查询条件 参数2 返回字段筛选 参数3配置
await wokersModel.find(q,null,qo)
.then(docs => {
ctx.body = { success: true, msg: 'ok', data: {docs,maxPage:maxPage,pageNow,totalCount} }
}).catch(err => {
ctx.body = { success: false, msg: 'no', data: {err,queryObj} }
})
await next()
})
.get('/byId', async (ctx, next) => {
// 获取工作人员通过_id 查询
if(!Object.isEmptyObject(ctx.request.query)){
await wokersModel.findById({_id:ctx.request.query.id})
.then(docs => {
/*
单个对象不是 数组
"docs":{
"interest":[
"ball23",
"women2"
],
"age":33,
"idNum":"idofe0.4479",
"contentinfo":"建立一个用户",
"schematext":1,
"_id":"5b36dce08ff32055448ebd8f",
"name":"w2",
"__v":0
},
*/
ctx.body = { success: true, msg: 'ok', data: {docs,body:ctx.request.query} }
}).catch(err => {
/*
id不存在的异常
{
"message":"Cast to ObjectId failed for value "{ _id: '5b36dce08ff32055448vbd8f' }" at path "_id" for model "wokers"",
"name":"CastError",
"stringValue":""{ _id: '5b36dce08ff32055448vbd8f' }"",
"kind":"ObjectId",
"value":{
"_id":"5b36dce08ff32055448vbd8f"
},
"path":"_id"
}
*/
ctx.body = { success: false, msg: 'no', data: err }
})
} else {
ctx.status = 400
ctx.body = { success: false, msg: 'no' }
}
await next()
})
// 建立工作人员
.post('/', async (ctx, next) => {
if(!Object.isEmptyObject(ctx.request.body)){
await wokersModel.create(ctx.request.body)
.then(docs => {
ctx.body = { success: true, msg: 'ok', data: {docs,body:ctx.request.body} }
}).catch(err => {
ctx.body = { success: false, msg: 'no', data: err }
})
} else {
ctx.status = 400
ctx.body = { success: false, msg: 'no' }
}
await next()
})
// 删除工作人员
.delete('/', async (ctx, next) => {
// 慎重 防止空对象
// function isEmptyObject(e) {
// var t;
// for (t in e)
// return !1;
// return !0
// }
// 复制对象
// let tmpPackage = JSON.parse(JSON.stringify(API_ROUTES.trademark));
// let cloned = Object.assign({}, source);
// let cloned = { ... source }; // 仅限ES6
if (!Object.isEmptyObject(ctx.request.body)) {
await wokersModel.remove(ctx.request.body)
.then(docs => {
// 可能不存在数据
console.log(docs.n==0)
if(docs.n==0){
ctx.body = { success: false, msg: 'no user', data: docs }
}else{
ctx.body = { success: true, msg: 'ok', data: docs }
}
}).catch(err => {
ctx.body = { success: false, msg: 'no', data: err }
})
} else {
ctx.status = 400
ctx.body = { success: false, msg: 'no' }
}
await next()
})
// 更新工作人员
.put('/', async (ctx, next) => {
if (!Object.isEmptyObject(ctx.request.body)) {
let newWorker = Object.assign({}, ctx.request.body)
delete newWorker.name
await wokersModel.update({ name: ctx.request.body.name }, { $set: newWorker })
.then(docs => {
/*
"docs":{
"n":1,
"nModified":1,
"ok":1
},
*/
if(docs.n==0){
ctx.body = { success: false, msg: 'no find', data: docs }
return
}
if(docs.nModified==0){
//修改失败
ctx.body = { success: false, msg: 'Modified fail', data: docs }
}else{
ctx.body = { success: true, msg: 'ok', data: {docs,newWorker} }
}
}).catch(err => {
ctx.body = { success: false, msg: 'no', data: err }
})
} else {
ctx.status = 400
ctx.body = { success: false, msg: 'no' }
}
await next()
})
.post('/test', async (ctx, next) => {
// ctx.body={
// body:ctx.request.body,
// files:ctx.request.files,
// fields:ctx.request.fields
// }
// console.log( typeof ctx.request.body )
ctx.body = {
body: ctx.request.body
}
await next()
})
// 主路由挂载
router.use('/workers', wokersRouter.routes(), wokersRouter.allowedMethods())
app.use(cors())
app.use(bodyParser())
app.use(router.routes(), router.allowedMethods())
app.listen(3002, () => {
console.log('app is run at http://localhost:3002')
})