关系型数据库与非关系型数据库
- 关系型数据库有mysql、oracle、db2、sql server等;
关系型数据库特点:关系紧密,由表组成;
优点:
易于维护,都是使用表结构,格式一致;
sql语法通用,可用于复杂查询;
缺点:
读写性能差,尤其是海量数据的高效率读写;
有固定的表结构,字段不可随意更改,灵活性稍欠;
高并发读写需求,对传统关系型数据库来说,硬件I/O读写是一个很大的瓶颈;
- 非关系型数据库(NoSQL)有MongoDB、Redis等
非关系型数据库特点:关系不紧密,有文档,有键值对;
优点:
格式灵活,存储数据的格式可以是key/value形式;
速度快,nosql可以内存作为载体,而关系型数据库只能使用硬盘;
易用,nosql数据库部署简单;
缺点:
不支持sql语法,学习和使用成本较高;
不支持事物;
复杂查询时语句过于繁琐;
MongoDB
MongoDB简介
MongoDB是为快速开发互联网web应用而设计的数据库系统,设计目标时极简、灵活,作为web应用栈的一部分;
MongoDB的数据模型是面向文档的,所谓文档是一种类似JSON的结构,简单理解MongoDB这个数据库中存的是各种各样的JSON(其实是BSON);此处文档就相当于关系型数据库中的一条数据,而关系型数据库中的一个表对应非关系型数据库中的一个集合;
MongoDB默认的端口号是27017;
基本命令
db // 查看当前操作在哪一个数据库
show dbs // 查看数据库列表(一共有几个数据库,若数据库为空,不出现在列表中)
use xxx // 切换到xxx数据库,若不存在,则创建一个xxx库
show collections // 展示当前数据库中所有的集合
// 新增数据
db.xxx.insert(文档对象) // 向当前数据库的xxx集合中插入一个文档
db.xxx.insertOne(文档对象) // 向当前数据库的xxx集合中插入一个文档
db.xxx.insertMany([文档对象,文档对象]) // 向当前数据的xxx集合中插入多条文档
// 删除数据
db.xxx.remove(查询条件) // 根据查询条件删除某些文档
// 查看数据
db.xxx.find(查询条件[,投影]) // 根据查询条件查询数据,投影为可选项,不加则返回该条文档的全部字段
db.xxx.findOne(查询条件[,投影]) // 只查找第一个找到的数据,应用于确认数据库中只存在一条数据的查找,可提高效率(查到一条不再继续查找)
// 修改更新数据
db.xxx.update(查询条件,要更新的内容[,配置对象]) // 更新查到的文档,若不加要更新的内容,则会将更换内容替换整个文档
例: db.xxx.update({name: '小明'}, {age: 19}) // 将会把查到的这条数据整体用name和age字段替换,其它自动就没了
db.xxx.updateOne(查询条件,要更新的内容[,配置对象]) // 更新查到的第一个文档
例:db.xxx.updateOne({name: '小明' }, {$set : {age : 20}}) // 将查到的name是小明的第一条数据的age修改为20,其余保持原来样子
db.xxx.updateMany(查询条件,要更新的内容[,配置对象]) // 更新查到的多条文档
例:db.xxx.update({name: '小明' }, {$set : {age : 20}}, {multi: true}) // 将查到的name是小明的所有数据的age修改为20,其余保持原来样子
上述投影是指:去掉不想要的数据(用0表示),只保留想要展示的数据(用1表示),0和1不能同时使用;
db.xxx.find({}, {_id: 0, name: 0}) // 查找到的数据只展示除_id与name字段
db.xxx.find({}, {age: 1}) // 查找到的数据只展示age字段
常用的操作符如下:
1、小于、 小于等于、 大于、大于等于、不等于 分别对应$lt、$lte、$gt、$gte、$ne
db.xxx.find({age: $lte: 20}) // 查找年龄小于等于20岁的人
2、逻辑或:使用$in 或 $or
db.xxx.find( {age: { $in[20, 30] }} ) // 查找年龄为20或30的人
db.xxx.find( {age: {$or[{age: 20}, {age: 30}]}}) // 查找年龄为20或30的人
3、逻辑非:使用$nin
db.xxx.find({age: {$nin: [20, 30]}}) // 查找年龄不是20或30岁的人
4、支持正则匹配条件
db.xxx.find({name: /^m/}) // 查找name以m开头的数据
5、支持where函数查找
db.xxx.find({$where: function() {
return this.name === '小明' && this.age === 18
}
}) // 查找名为小明并且年龄是18的数据
mongoose的使用
mongoose是一个在node平台下,用于帮助开发者连接mongodb的包(它是一个对象文档模型ODM库),它对node原生的MongoDB模块进行了进一步的优化封装,并提供了更多的功能,可以更加简单、方便、安全、稳定的操作mongoDB);
mongoose的使用包括四个步骤:
- 引入mongoose
- 连接数据库(并绑定监听)
- 创建模型对象(模型对象上绑定了方法)
- 操作数据库(通过模型对象进行增删改查等)
// index.js文件
let mongoose = require('mongoose') // 引入mongoose
// 连接数据库
// mongodb://127.0.0.1:27017/xxx 表示连接的哪台服务器上的xxx数据库
mongoose.connect('mongodb://127.0.0.1:27017/xxx', {
useNewUrlParser: true, // 使用一个新的url解析器,用于解决一些安全性问题
useUnifiedTopology: true // 使用一个统一的新的拓扑结构
})
// 绑定数据库连接的监听
mongoose.connection.on('open', function(err) {
if(err) {
console.log('数据库连接失败', err)
} else {
console.log('数据库连接成功')
// 在此处做一些数据库的增删改查操作
}
})
模式对象与模型对象
模式对象即Schema,可通过Schema对集合进行约束;通过mongoose.Schema即可后对其进行约束;
// 引入mongoose
let mongoose = require('mongoose')
let Schema = mongoose.Schema
// 对其进行约束
let studentsRule = new Schema({
stu_id: {
type: String, // 限制为字符串
required: true, // 限制必填
unique: true // 限制学号唯一
},
name: {
type: String, // 限制为字符串
required: true, // 限制必填
},
sex: {
type: String, // 限制为字符串
required: true, // 限制必填
},
hobby: [String], // 限制为字符串数组
info: Schema.Types.Mixed, // 接收所有类型
date: {
type: Date,
default: Date.now() // 设置默认值
}
})
模型对象相当于数据库中的集合,通过该对象可对集合进行操作;
将创建好的约束与某个集合进行匹配,即可得到模型对象;
// 接上面代码
let stuModel = mongoose.model('students', studentsRule) // 将studentsRule与students集合匹配, stuModel即是模型对象
利用moogose进行CRUD
// 增加数据
模型对象.create(文档对象, 回调函数)
// 删除数据,没有delete方法!
模型对象.deleteOne(查询条件, 回调函数)
模型对象.deleteMany(查询条件, 回调函数)
// 更新修改数据 update方法已被弃用
模型对象.updateOne(查询条件,要更新的内容[, 配置对象], 回调函数)
模型对象.updateMany(查询条件,要更新的内容[, 配置对象], 回调函数)
// 查看数据
模型对象.find(查询条件[, 投影], 回调函数) // 若查找结果为空,返回一个空数组[]
模型对象.findOne(查询条件[, 投影], 回调函数) // 若查找结果为空,返回一个空对象{}
mongose的模块化开发
在实际应用中,由于要建立很多个collection,相对应的就要有很多个模型对象,杂糅在一起就会比较冗余且不好维护,因此需要模块化开发~(示例如下)
// app.js 文件 用于连接及操作数据库
const mongoose = require('mongoose')
const stuModel = require(__dirname + '/model/students') // 引入students模型对象
const teaModel = require(__dirname + '/model/teachers') // 引入teachers模型对象
mongoose.set('strictQuery', true);
mongoose.connect('mongodb://127.0.0.1:27017/demo')
mongoose.connection.on('open', (err) => {
if (err) {
console.log('数据库连接失败')
} else {
// 连接成功则操作数据库
// 给students集合插入一条文档
stuModel.create({"stu_id": 101, "name": "小王", "age": "13"}, (err)=> {
if (err) {
console.log(err)
} else {
console.log('students插入成功')
}
})
// 给students集合插入一条文档
teaModel.create({"tea_id": 101, "name": "吴老师", "age": "37"}, (err)=> {
if (err) {
console.log(err)
} else {
console.log('teachers插入成功')
}
})
console.log('数据库连接成功')
}
})
// students.js文件
const mongoose = require('mongoose')
var Schema = mongoose.Schema
let studentsRule = new Schema({
stu_id: {
type: String, // 限制为字符串
required: true, // 限制必填
unique: true // 限制名称唯一
},
name: {
type: String, // 限制为字符串
required: true, // 限制必填
unique: true // 限制名称唯一
},
age: {
type: String, // 限制为字符串
required: true, // 限制必填
}
})
// 将studentsRule与students集合匹配, stuModel即是模型对象
let stuModel = mongoose.model('students', studentsRule)
module.exports = stuModel
// teachers.js 文件
const mongoose = require('mongoose')
var Schema = mongoose.Schema
let teachersRule = new Schema({
tea_id: {
type: String, // 限制为字符串
required: true, // 限制必填
unique: true // 限制名称唯一
},
name: {
type: String, // 限制为字符串
required: true, // 限制必填
unique: true // 限制名称唯一
},
age: {
type: String, // 限制为字符串
required: true, // 限制必填
}
})
// 将studentsRule与students集合匹配, stuModel即是模型对象
let teaModel = mongoose.model('teachers', teachersRule)
module.exports = teaModel
文件结构如下:
控制台输出结果为:
进一步地,可将数据库连接成功或失败后的操作,封装成一个函数,如下:
// 该模块用于连接数据库
const mongoose = require('mongoose')
const opeartion = require('./operation')
mongoose.set('strictQuery', true);
mongoose.connect('mongodb://127.0.0.1:27017/demo')
mongoose.connection.on('open', (err) => {
if (err) {
opeartion(err) // 调用opration错误处理方法
} else {
opeartion() // 调用opration正确处理方法----操作数据库
}
})
// 该文件用于处理数据库连接成功或失败的后续操作,一般在此进行数据库的增删改查操作
const stuModel = require(__dirname + '/model/students') // 引入students模型对象
const teaModel = require(__dirname + '/model/teachers') // 引入teachers模型对象
function operation(err) {
if(err) {
console.log(err)
} else {
// 给students集合插入一条文档
stuModel.create({"stu_id": 103, "name": "小朋友", "age": "13"}, (err)=> {
if (err) {
console.log(err)
} else {
console.log('students插入成功')
}
})
// 给students集合插入一条文档
teaModel.create({"tea_id": 103, "name": "大朋友", "age": "37"}, (err)=> {
if (err) {
console.log(err)
} else {
console.log('teachers插入成功')
}
})
}
}
module.exports = operation // 将该函数暴露出去
students.js与teachers.js如上面文件一样,文件结构如下:
控制台输出结果如下: