毕业设计数据库部分(mongodb+express+mongoose实战)

数据库部分

数据库采用了mongo,使用mongoose来进行操作数据库,mongoose相关知识看下面的文章自行学习:

Nodejs学习笔记(十四)— Mongoose介绍和入门

数据库连接配置
var mongoose = require('mongoose');
var dbUrl = 'mongodb://127.0.0.1:27017/examSystem';
var db = mongoose.connect(dbUrl, { useNewUrlParser: true });
 
db.connection.on('error', function(error) {
    console.log('数据库链接失败:' + error);
});
db.connection.on('connected', function() {
    console.log('数据库链接成功!');
});
db.connection.on('disconnected', function() {
    console.log('Mongoose connection disconnected');
});
module.exports = db;

schema是mongoose里会用到的一种数据模式,可以理解为表结构的定义,特点为

  1. 每个schema会映射到mongodb中的一个collection,它不具备操作数据库的能
  2. 对每个定义的生成一个Good的model并导出,model是由schema生成的模型,可以对数据库的操作

本系统的schema代码如下:

//papers.js
const mongoose = require('mongoose');
let Schema = mongoose.Schema;
let paperSchema = new Schema({
    name: String, //试卷名
    totalPoints: Number, //试卷总分
    time: Number, //考试总时长
    startTime: Date, //考试开始时间
    examgrade: Number, //考试年级
    examclass: Number, //考试班级
    status: Number, //状态,0表示没开考,1表示开考了但是没阅卷,2表示已阅卷
    _teacher: {
        type: Schema.Types.ObjectId,
        ref: 'Teacher'
    }, // 出卷老师
    _questions: [{
        type: Schema.Types.ObjectId,
        ref: 'Question'
    }]
})
module.exports = mongoose.model('Paper', paperSchema);
const mongoose = require('mongoose');
let Schema = mongoose.Schema;
let questionSchema = new Schema({
    _teacher: {
        type: Schema.Types.ObjectId,
        ref: 'Teacher'
    }, //出题老师
    _papers: [{
        type: Schema.Types.ObjectId,
        ref: 'Paper'
    }], //所属试卷
    content: String, //内容
    type: {
        type: String,
        enum: [ //类型
            'single', //单选
            'multi', //多选
            'apfill', //填空题
            'Q&A', //简答
            'judgement' //判断
        ]
    },
    score: Number, //分数
    answer: String, //答案
    selection: Array, //选项
    useState: Number, //使用状态,0表示可以使用并没有开考的试卷,1表示题目对应有试卷开考了,2表示题目失效了,失效的题目就是题目存在所属试卷,但是老师又把它删了,目前看来状态0和1好像没用了,因为只要题目被试卷引用了,题目就设置为失效,但是因为相关代码都写了,就不删了,怕后面又要用到这俩状态。
});
module.exports = mongoose.model('Question', questionSchema);
const mongoose = require('mongoose');
let Schema = mongoose.Schema;
let studentSchema = new Schema({
    userId: Number, //学号
    userName: String, //姓名
    password: String, //密码
    grade: Number, //年级
    class: Number, //班级
    exams: [{ //参加的考试
        _paper: {
            type: Schema.Types.ObjectId,
            ref: 'Paper'
        }, //试卷
        date: Number, //考试总时长
        examStatus: Number, //0表示没开考,为1表示开考了没阅卷,为2表示阅卷了,为3表示试卷没有主观题且暂存答案,为4表示试卷有主观题且暂存答案
        score: Number, //考试分数
        startTime: Date,
        answers: [{
            _question: {
                type: Schema.Types.ObjectId,
                ref: 'Question'
            },
            answer: String
        }]
    }]
});
module.exports = mongoose.model('Student', studentSchema);
const mongoose = require('mongoose');
let Schema = mongoose.Schema;
let teacherSchema = new Schema({
    userId: Number, // 教师工号
    userName: String, // 姓名
    password: String, // 密码
    _papers: [{ type: Schema.Types.ObjectId, ref: 'Paper' }], //试卷
    _questions: [{
            type: Schema.Types.ObjectId,
            ref: 'Question'
        }] //问题
});
module.exports = mongoose.model('Teacher', teacherSchema);
主要涉及到的mongo操作
新建记录(以教师注册为例)
     let user = req.body.user;//前端发送过来的用户数据,格式同数据库数据格式
     Teacher.create(user, (err1, doc1) => {
                    if (err1) {
                        res.json({
                            status: '1',
                            msg: err1.message
                        })
                    } else {
                        if (doc1) {
                            res.json({
                                status: '0',
                                msg: 'success'
                            })
                        } else {
                            res.json({
                                status: '3',
                                msg: '注册失败'
                            })
                        }
                    }
                })

下面的代码只列出关键语句,那些if else之类的和上面相同

搜索记录
Teacher.findOne({
        userId: userId
    }, (err, doc) => {})//返回含有符合条件的对象
//--------------------------------------------  
Teacher.find({
        userId: userId
    }, (err, doc) => {})//返回含有符合条件的数组
//--------------------------------------------
Teacher.find({
        name: new RegExp(name, 'i')
    }, (err, doc) => {})//模糊搜索,不分大小写
//--------------------------------------------
let searchParams,i=0;
if(i==1){
     searchParams={name:1,id:1}
}else{
	 searchParams={name:0,id:0}
}
Teacher.find(searchParams, (err, doc) => {})//定义查询参数查询
//--------------------------------------------
let idArr=[1,2,3];
Teacher.find({
         "_id": { $in: idArr},
}, (err, doc) => {})//搜索id为1或id为2或id为3的记录,$in的介绍见下文技术要点
//-------------------------------------------
Teacher.find({
         "_id": {  $ne:2 },
}, (err, doc) => {})//搜索id不为2的记录,$ne的介绍见下文技术要点

分页

//----------
limit 是 pageSize,skip 是第几页*pageSize,例如:
db.goods.find().skip(2).limit(4):跳过前2条数据来到第三条,查询共4条数据,即查第3,4,5,6条数据分页
db.goods.find().skip(0).limit(4):查询第1页的内容,第1页一共4条数据
db.goods.find().skip(4).limit(4):查询第2页的内容,第2页一共4条数据
db.goods.find().skip(8).limit(4):查询第3页的内容,第3页一共4条数据
所以在毕设中,分页写为:
    let pageSize = parseInt(req.param("pageSize")); //每页条数
    let pageNumber = parseInt(req.param("pageNumber")); //第几页
    let skip = (pageNumber - 1) * pageSize; // 跳过几条数据
    Question.find({
         "content": reg,
     }).skip(skip).limit(pageSize)
     .exec((err2, doc2) => {}

对文档集合中的数组元素进行分页使用$slice,$slice介绍如下:
在这里插入图片描述
所以在毕设中,对学生的考试记录进行分页,代码为(populate介绍见下文):

    let pageSize = parseInt(req.param("pageSize")); //每页条数
    let pageNumber = parseInt(req.param("pageNumber")); //第几页
    let skip = (pageNumber - 1) * pageSize; // 跳过几条
    Student.findOne({
        "userId": userId,
    }, {
        "exams": {
            $slice: [skip, pageSize]
        }
    }).populate({
        path: 'exams._paper',
        select: 'name status _questions',
        match: {
            name: reg
        }
    }).exec((err1, doc1) => {})

参考文档:MongoDB学习 (六):查询

连接查询

技术要点:

查询语句:Query.populate(path, [select], [model], [match], [options])
path:指定要填充的关联字段,可以理解为在表中定义的外键名,如果外键定义在数组内(比如学生表),那么使用的时候就直接写“数组名.属性名”
select:指定填充 document 中的哪些字段,比如连接查询想查到对应的name,那么就select:name
model:指定关联字段的 model,如果没有指定就会使用Schema的ref,这个查询一般不会写
match:指定附加的查询条件,相当于对查询后的结果做一个筛选
options:指定附加的其他查询选项,如排序以及条数限制等等

试卷表用_questions为外键,如果想查看试卷中的信息以及对应题目的全部,那么连接查询代码写为:
  let paperId="5ce80e8215bd0b06c82573e9";
Paper.findOne({
        '_id': paperId
    }).populate({
        path: '_questions'
    }).exec((err1, doc1) => {}
查询结果见下图1
//----------------------------------  
学生表的schema结构为:
let studentSchema = new Schema({
    ...
    exams: [{ //参加的考试
        _paper: {
            type: Schema.Types.ObjectId,
            ref: 'Paper'
        }, //试卷
    ...
    }]
});
所以要查看学生的试卷以及试卷的name status _questions三个值,查询语句为:
    Student.findOne({
        "userId": userId,
    }, {
        "exams": {
            $slice: [skip, pageSize]
        }
    }).populate({
        path: 'exams._paper',
        select: 'name status _questions',
    }).exec((err1, doc1) => {})
查询结果如下右图:

在这里插入图片描述在这里插入图片描述

学习文档:Mongoose 之 Population 使用

删除操作

数组删除见下方数组修改的删除部分

非数组删除使用remove方法,remove方法介绍如下:

db.collection.remove(
   <query>,//查询语句
   {
     justOne: <boolean>,(可选)如果设为 true1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
   }
)

例如删除试卷:

          Paper.remove({
                    "_id": {
                        $in: paperId
                    }
                }, function(err1, doc1) {})
修改操作
修改操作之非数组修改

update方法介绍:

db.collection.update(
   <query>,//查询语句
   <update>,//update对象和一些更新操作符
   {
     upsert: <boolean>,//如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入
     multi: <boolean>,//只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新,默认是false
   }
)

修改方法一:
先定义要修改的值,然后使用update方法修改,例如修改教师信息:

let user = req.body.user;//前端发来的数据
Teacher.update({
         "userId": user.userId
   }, user, (err2, doc2) => {})

修改方法二:
直接使用$set和update修改,例如修改试卷考试状态:

let paperId = req.body.paperId;//前端发来的数据
Paper.update({
        '_id': paperId
    }, {
        '$set': {
            'status': 2
        }
    }, (err1, doc1) =>  {})

修改方法三:
首先使用findOne找到对象,然后对对象结果进行操作,然后使用.save()方法保存对象,例如教师表添加新增的题目的_id,就是先找到教师信息,然后新增题目,然后把新增题目的_id加入教师信息中,然后使用.save()方法保存:

 Teacher.findOne({
        "userId": teacherId,
    }, (err2, doc2) => {
       ...
         if (doc2) {
          questionData.forEach(item => {
            item._teacher = doc2._id;
          })
         Question.create(questionData, function(err, doc) { //创造题目               
            ...
            if (doc) {
              doc.forEach(item2 => {
                 doc2._questions.push(item2._id);
              })
             doc2.save();//使用save方便保存修改
             ..... 
修改操作之数组修改

技术要点:

$push:向文档数组中添加元素,如果没有该数组,则自动添加数组。
$addToSet:添加值到一个数组中去,如果数组中已经存在该值,那么将不会有任何的操作。
$pull:删除数组元素,将所有匹配的元素删除。
$each:可用于一次表示添加多个值数组,若只想添加一个值,则数组只放一个值就好。
$ne:不等于,例如查询x不等于3 的数据:db.things.find( { x : { $ne : 3 } } );
$in:包含,可用于查询某一范围内的值,例如查询x 的值为2、4、6的数据,可写为
        db.things.find({x:{$in: [2,4,6]}});
$set:替换掉指定字段的值

参考文档:
spring mongodb数组修改器— p u s h 、 push、 pushne、 a d d t o s e t 、 addtoset、 addtosetpop、$pull
MongoDB高级查询

添加和删除以教师表为例,教师表结构:

  1. 数组添加新值
    向_papers数组插入多个新的questionId:
    插入语句为:
let questionId=["5ce80d3e15bd0b06c82573e4","5ce80d3e15bd0b06c82573e5"];
Teacher.update({
        "_id": teacherId,
    }, {
        "$addToSet": {
            "_questions": {
                "$each": questionId
            }
        }
    }, (err, doc) => {...})

参考文档:MongoDB数组更新操作$addToSet和$each修饰符

  1. 删除数组的多个数据
    删除_papers数组多个questionId:
let questionId=["5ce80d3e15bd0b06c82573e4","5ce80d3e15bd0b06c82573e5"];
Teacher.update({
        "_id": teacherId,
    }, {
        "$pull": {
            "_questions": {
                "$in": questionId
            }
        }
    }, (err, doc) => {...})
  1. 修改数组操作
    占位符$技术要点:
  • 1.占位符$的作用主要是用于返回数组中第一个匹配的数组元素值(子集),例如下列集合:
 { "_id" : 2, "semester" : 1, "grades" : [ "901", "902", "903" ] },
 { "_id" : 3, "semester" : 1, "grades" : [  "9021", "9022", "9023"  ] },
 { "_id" : 4, "semester" : 1, "grades" : [  "9031", "9032", "9033" ] },
 { "_id" : 5, "semester" : 1, "grades" : [ "80", "95", "96" ] },

模糊查询所grades含有“90”的记录如正下方图:                                  加上$的结果如正下方图:
在这里插入图片描述在这里插入图片描述

  • 2.在更新时未显示指定数组中元素位置的情形下,占位符$用于识别元素的位置,也就是说,当要修改数组中的元素时,如果不知道数组中元素的位置,可以使用位置$操作符,但是修改的时候也只会修改第一个匹配到的子集记录,如下图:
    在这里插入图片描述
    在这里插入图片描述
  • 更新数组内嵌文档样式可以使用.$.成员方式,例如上面学生表的结果更新exam的date字段,可写为:exams.$.date
    以学生表为例,学生表结构:
    在这里插入图片描述
    例如:对于上面的学生表结构,当想要修改paperId为1的数据的date值时,语句写成:
let peparId=1;
Student.updateMany({
      "exams._paper": paperId,
    }, {
      $set: { "exams.$.date": paperData.time }
  }, (err4, doc4) => {})

参考文档:
Mongodb数组操作$(update)、$占位符更新嵌套数组、嵌套文档集合
MongoDB 数组元素增删改

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值