了解数据库
- 关系型数据库是一种基于关系模型的数据库。
- 数据以表格的形式存储,表格中的每一行是一个记录,每一列是一个字段,每个字段都有一个数据类型。关系型数据库使用结构化查询语言(SQL)来查询和管理数据。
- 优点:数据结构清晰、数据关系明确、数据一致性好。
- 缺点:可拓展性受限。不适合处理海量数据和非结构化数据。
- ==非关系型数据库(NoSQL)==是一种非结构化的数据库。
- 数据以键值对、文档、图形等形式存储。非关系型数据库不需要预定义的模式,可以随时添加新的字段和数据类型。非关系型数据库通常使用非结构化查询语言来查询和管理数据。
- 优点:可拓展性高、适合处理非结构化数据和海量数据、支持分布式部署。
- 缺点: 数据结构不够清晰、数据关系不够明确、数据一致性稍差。
总的来说,关系型数据库适合处理结构化数据,如订单、账户等;非关系型数据库适合处理大数据、非结构化数据和实时数据,如用户日志,社交媒体数据等。初学者可以根据自己的需求选择合适的数据库。
mongoose的使用
引入mongoose并连接mongodb
const mongoose = require('mongoose');
// 连接指定数据库(如果不存在就需要先创建数据库)
mongoose
.connect('mongodb://localhost:27017/ami')
.then(() => console.log('connected!'));
预设表规则并创建相应的表
// 获取设置表规则的操作对象 => schema 提要,纲要
const { Schema } = mongoose;
// 预设的表规则
const userSchema = new Schema(
{
name: {
type: String,
/* 限制字符串的长度 */
maxLength: 10,
minLength: 1,
},
age: {
type: Number,
required: true, //必填
/* 对数字大小做验证 */
min: 0,
/* 你希望给用户一个提示 */
max: [150, '年龄不可超过150,不要太离谱!'],
},
sex: {
type: String,
/* 枚举:预设字段值内容 */
enum: ['男', '女'],
},
tag: {
type: Array,
validate: {
/* 校验的逻辑 */
validator(value) {
/* value => tag字段值 */
/*
对value进行一系列的校验判断
*/
/* 返回true或者false */
},
message: 'tag字段的报错信息',
},
},
hobbies: String,
},
{
versionKey: false, //去除版本号
}
);
// 创建表(得到表的操作对象)
const userInfoTable = mongoose.model('userInfoTable', userSchema);
增加数据
// 增加数据 ==> 批量添加
userInfoTable
.create(
{
// _id: new mongoose.Types.ObjectId(), //mongodb会帮你自动创建id域名,无需自己写
name: '可乐',
age: 17,
sex: '男',
tags: '帅气,聪明'.split(','),
hobbies: '打篮球',
},
{
// _id: new mongoose.Types.ObjectId(), //mongodb会帮你自动创建id域名,无需自己写
name: 'ami',
age: 161,
sex: '男',
tags: '帅气,聪明'.split(','),
},
...
)
.then(() => {
console.log('success!');
})
.catch(() => {
console.log('failure');
});
查找数据
findOne()、findById()、find()
userInfoTable
.findOne({
age: 161,
})
.then((value) => console.log(value));
userInfoTable
.findById({
_id: '6453aed985f7f27723c1999e',
})
.then((value) => console.log(value));
// 返回结果数组,查不到结果返回空数组
userInfoTable.find({ age: 161 }).then((value) => console.log(value));
find()之模糊查询
/*
模糊查询:
=> 通过条件操作符来实现
比较查询操作符(适用于数字):
$gt | $lt | $gte | $lte | $eq | $ne | => 大于 | 小于 | 大于等于 | 小于等于 | 等于 | 不等于
逻辑查询操作符(判断):
$or | $and |$nor => 或 | 与 | 非
存在判断(适用于数组):
$exists:true | false; ==> 判断是否存在某一字段名
$in | $nin | $size ==> 判断数组长度 | $all
$where 遍历数据库,由返回的boolean值决定数据的去留
正则表达式:===> eg. find({name:/a/,})
*/
比较查询操作符的使用
userInfoTable
.find({
// 当值不再是一个具体的值的话,用对象的形式表示
age: {
// $lt: 18, //小于18
// $lte: 18, //小于等于18
// $gt: 18, //小于18
// $gte: 18, //大于等于18
// $eq: 16 //等于16
$ne: 16, //不等于16
},
})
.then((userArr) => console.log(userArr));
逻辑查询操作符的使用
userInfoTable
.find({
// 多个条件里,能满足任意一个条件的数据就是符合
$or: [
{
age: {
$gt: 16,
},
},
{
sex: '女',
},
],
// 多个条件都要满足
// and 用的比较少,因为find参数就符合and
$and: [
{
age: {
$gt: 16,
},
},
{
sex: '女',
},
],
// 多个条件均不满足时符合
$nor: [
{
age: {
$gt: 16,
},
},
{
sex: '女',
},
],
})
.then((userArr) => console.log(userArr));
存在判断(适用于数组)以及$where的使用
userInfoTable
.find({
tags: {
// 当前字段值(数组)中是否存在该值
// $in: '帅气',
// 当前字段值中存在任意一种值的数据就符合!!!!!!!!!!!!
// $in: ['聪明', '帅气'],
// 不存在
// $nin: '帅气',
// $nin: ['聪明', '帅气'],
},
hobbies: {
// 是否存在该字段
$exists: true,
},
tags: {
// $size: 3, //数组长度为3
$all: ['帅气', '聪明'], //数组值中存在所有条件值时才符合
},
// $where 遍历数据库,由返回的boolean值决定数据的去留
$where: function () {
// return true 表示保留该条数据 ==> 类似于过滤
return this.age > 16;
},
name: /a/,
})
.then((userArr) => console.log(userArr));
find()中参数projection、options的使用
/*过滤字段:使用find()函数的第二个参数projection*/
/*处理查询的数据:使用find()函数的第三个参数options*/
userInfoTable
.find(
{
$where: function () {
return this.tags.length > 1;
},
},
/* 过滤字段名 */
{
name: true, //只取name字段,区域字段名过滤掉
tags: true,
_id: false, //过滤掉该字段名,
},
/* 对查询到的数据进行处理 */
{
// 排序:降序、升序
sort: {
// age: 1, //升序
age: -1, //降序
},
/* 跳过前n条结果 */
skip: 6,
/* 去除n条数据 */
limit: 3,
/*
实现分页:
12条数据,4条数据为1页
通过skip 和 limit 配合使用
*/
}
)
.then((userArr) => console.log(userArr));
删除数据 deleteMany、deleteOne
注意:
- 最好基于独一无二的值进行删除
- 数据库权限的分配(一般不太会让你有删除重要数据的权限 ==> 数据库工程师的工作)、
userInfoTable
.deleteMany({
age: 156,
})
.then((data) => {
/*
打印的data:{ acknowledged: true, deletedCount: 0 }
acknowledged: 成功状态为true
deletedCount: 成功删除了几条
*/
console.log(data);
});
更新(修改)数据 updateOne、updateMany、findByIdAndUpdate
- updateOne 修改查询到的第一条数据
- updateMany 修改所有查询到的数据
userInfoTable
.updateOne(
// 查询条件
{
name: '可乐',
},
/* 要修改成什么内容 */
{
/* 同时修改多个字段的值 */
$set: {
name: '可乐' + 1,
age: 20,
},
}
)
.then((data) => {
/*
{
acknowledged: true,
modifiedCount: 1,
upsertedId: null,
upsertedCount: 0,
matchedCount: 1
}
*/
console.log('更新成功', data);
});
更新数据之对数组的更新
userInfoTable
.updateMany(
// 查询条件
{
name: '索隆1',
tags: {
// 元素匹配
$elemMatch: {
/* 存在时,会返回成员的下标 */
$in: '五一加班',
},
},
},
/* 要修改成什么内容 */
{
/* 同时修改多个字段的值 */
$set: {
name: '索隆' + 1,
age: 20,
},
/* 修改数组的值 */
/*
$set: {
// 直接覆盖 ===> 性能低
tags: ['三刀流', '独眼'],
},
*/
/* 仅针对于数组的追加(允许添加重复值)*/
$push: {
/* tags: {
// 逐项添加
$each: ['聪明', '帅气'],
}, */
/* 直接添加数组 */
tags: ['聪明', '帅气'],
},
/* 去重的数组追加 */
$addToSet: {
tags: {
$each: ['聪明', '帅气'],
},
},
/* 修改数组中指定下标的值 */
$set: {
'tags.2': '五一加班',
},
/* 删除数组中的成员 */
$pop: {
/* 从前面开始往后删除一个 */
// tags:-1
/* 从后面开始往前删除一个 */
tags: 1,
},
/* 基于值,删除数组中指定成员 */
$pull: {
tags: '五一不加班',
},
/* 一次性删除多项成员值 */
$pull: {
tags: {
$in: ['聪明', '帅气'],
},
},
/* 删除字段(基本不用) */
$unset: {
sex: true,
},
}
/* 获得符合条件的数组匹配数组元素的下标 */
// {
// /* 经过元素匹配后,如果存在“五一加班”的成员,会返回该成员的下标存在$中 */
// $set: {
// 'tags.$': '五一不加班',
// },
// }
)
.then((data) => {
/*
data : {
acknowledged: true,
modifiedCount: 1,
upsertedId: null,
upsertedCount: 0,
matchedCount: 1
}
*/
console.log('更新成功', data);
});
表关联
一般是某一张表中的字段值需要是对象的时候,会新创建一个表用以关联
let scoreSchema = new Schema({
name: String,
subject: {
type: String,
},
result: Number,
/* 定义关联字段 */
refStudent: {
/* 通过唯一性的ID去关联 */
type: mongoose.Types.ObjectId,
// ref 关联目标表
ref: 'student', //实际的表名
},
});
let studentInfoTable = mongoose.model('student', studentSchema);
let scoreInfoTable = mongoose.model('score', scoreSchema);
联表查询
scoreInfoTable
.find({
name: '李华',
})
.populate({
/* 当前表的关联字段 */
path: 'refStudent',
/* 关联表 */
model: studentInfoTable,
})
.then((res) => {
console.log(res);
});