nodeJS——Mongoose基础操作
Mongoose
- 1. Mongoose
- 1.1 Mongoose操作
- 1.1.1 新增
- 1.1.2 字段值验证
- 1.1.3 批量新增 `insertMany()`
- 1.1.4 删除文档 `deleteOne()` & 批量删除文档 `deleteMany()`
- 1.1.5 更新数据 `updateone()` & 批量更新数据`updateMany()`
- 1.1.6 查询数据 `findOne()` & 根据Id查询数据`findById()` & 批量查询数据 `find()` & 条件查询`find(条件)`
- 1.1.7 逻辑运算 $or & $and
- 1.1.8 .select()
- 1.1.9 .sort()
- 1.2 Mongoose建议封装
1. Mongoose
Mongoose
是一个基于 Node.js
的 ODM
(对象文档映射)库,它为 MongoDB
提供了一个结构化的解决方案来定义数据模型,并通过模式(Schema
)验证数据。
相对于Mongo Shell
(命令行工具)而言:
Mongoose
简化开发流程,提供了许多高级功能,如预/后钩子(pre/post hooks
)、虚拟字段(virtual fields
)、中间件(middleware
)等,可以简化应用程序的开发过程。
集成到应用逻辑中,由于它是作为 npm
包提供的,所以可以直接集成到Node.js
应用程序中,使开发者能够在应用程序层面上处理 MongoDB 数据库操作。
对于Mongo Shell
:
Mongo Shell
直接操作数据库,通过CMD启动Mongosh
,Mongo Shell
是一个交互式的 JavaScript
环境,允许你直接对 MongoDB
数据库执行命令。它非常适合用来进行数据库管理、测试查询语句以及执行各种数据库操作。对于初学者来说,使用Mongo Shell
可以更直观地了解 MongoDB
的工作原理,包括数据模型设计还有查询优化等等。
1.1 Mongoose操作
// 1. 安装mongoose
// 2. 导入mongoose
const mongoose = require('mongoose');
// 3. 连接数据库服务
// 连接方法 协议名称 ip地址 要操作的数据库名称(后续操作的数据库)
mongoose.connect('mongodb://127.0.0.1:27017/bilbil');
// 4. 设置回调
// 成功回调
mongoose.connection.once('open', () => {
console.log('连接成功');
})
// 错误回调
mongoose.connection.on('error', () => {
console.log('连接失败');
})
// 关闭回调
mongoose.connection.on('close', () => {
console.log('连接关闭');
})
1.1.1 新增
// 1. 安装mongoose
// 2. 导入mongoose
const mongoose = require('mongoose');
// 3. 连接数据库服务
// 连接方法 协议名称 ip地址 要操作的数据库名称(后续操作的数据库)
mongoose.connect('mongodb://127.0.0.1:27017/bilbil');
// 4. 设置回调
// 成功回调
mongoose.connection.once('open', () => {
console.log('连接成功');
// 5. 创建文档的结构对象
// Schema可以理解是【模式】的意思,也就是创建一个文档对象,约束文档属性和属性值
let BookSchema = new mongoose.Schema({
name: String,
author: String,
price: Number,
is_hot: Boolean,
tags: Array,
pub_time: Date,
// Buffer Buffer对象
// Mixed 可以理解成Any
// ObjectId 联合查询使用,
// Decimal128 高精度类型
});
// 6. 创建模型对象 模型对象:对文档操作的封装对象
// BookModel可以对指定文档进行增删改查
// model是一个方法 books是集合名称 BookSchem是结构对象
let BookModel = mongoose.model('books', BookSchema);
// 7. 新增
// BookModel.create({
// name: '西游记',
// author: '吴承恩',
// price: 19.9
// }, (err, data) => {
// // 形参1
// if (err) {
// console.log('报错', err);
// return;
// };
// // 形参2
// // data 插入成功后的文档对象
// console.log(data);
// });
// 7.1 create的回调方法被弃用了
BookModel.create({ name: '西游记', author: '吴承恩', price: 19.9, is_hot: true, tags: ['社会', '玄幻'], pub_time: new Date() }).then(data => {
console.log('data', data);
// 8. 关闭数据库连接 项目中不会写这段
mongoose.disconnect();
}).catch(err => {
console.log('err', err);
})
});
// 错误回调
mongoose.connection.on('error', () => {
console.log('连接失败');
})
// 关闭回调
mongoose.connection.on('close', () => {
console.log('连接关闭');
})
1.1.2 字段值验证
// 1. 安装mongoose
// 2. 导入mongoose
const mongoose = require('mongoose');
// 3. 连接数据库服务
// 连接方法 协议名称 ip地址 要操作的数据库名称(后续操作的数据库)
mongoose.connect('mongodb://127.0.0.1:27017/bilbil');
// 4. 设置回调
// 成功回调
mongoose.connection.once('open', () => {
console.log('连接成功');
// 5. 创建文档的结构对象
// Schema可以理解是【模式】的意思,也就是创建一个文档对象,约束文档属性和属性值
let BookSchema = new mongoose.Schema({
name: {
type: String,
required: true, // 必传
unique: true // 重建集合才有效果,报错err MongoServerError: E11000 duplicate key error collection: bilbil.books index: name_1 dup key: { name: "西游记" }
},
author: {
type: String,
default: '吴承恩' // 默认值
},
style: {
type: String,
enum: ['言情', '励志']
},
price: Number,
is_hot: Boolean,
tags: Array,
pub_time: Date,
// Buffer Buffer对象
// Mixed 可以理解成Any
// ObjectId 联合查询使用,
// Decimal128 高精度类型
});
// 6. 创建模型对象 模型对象:对文档操作的封装对象
// BookModel可以对指定文档进行增删改查
// model是一个方法 books是集合名称 BookSchem是结构对象
let BookModel = mongoose.model('books', BookSchema);
// 7. 新增
// 7.1 create的回调方法被弃用了
BookModel.create({ name: '西游记', price: 19.9, is_hot: true, tags: ['社会', '玄幻'], style: "励志", pub_time: new Date() }).then(data => {
console.log('data', data);
// 8. 关闭数据库连接 项目中不会写这段
mongoose.disconnect();
}).catch(err => {
console.log('err', err);
})
});
// 错误回调
mongoose.connection.on('error', () => {
console.log('连接失败');
})
// 关闭回调
mongoose.connection.on('close', () => {
console.log('连接关闭');
})
1.1.3 批量新增 insertMany()
let data = [
{ name: '西游记', price: 19.9, is_hot: true, tags: ['社会', '玄幻'], style: "励志", pub_time: new Date() },
{ name: '红楼梦', author: '曹雪芹', price: 19.9, is_hot: true, tags: ['社会', '思考'], style: "励志", pub_time: new Date() }
]
BookModel.insertMany(data).then(data => {
console.log('data', data);
// 8. 关闭数据库连接 项目中不会写这段
mongoose.disconnect();
}).catch(err => {
console.log('err', err);
})
1.1.4 删除文档 deleteOne()
& 批量删除文档 deleteMany()
// deleteOne
BookModel.deleteOne({ _id: '6756c7b624d6410777458c8f' }).then(data => {
console.log('data', data);
// 8. 关闭数据库连接 项目中不会写这段
mongoose.disconnect();
}).catch(err => {
console.log('err', err);
})
// deleteMany
BookModel.deleteMany({ author: '曹雪芹' }).then(data => {
console.log('data', data);
// 8. 关闭数据库连接 项目中不会写这段
mongoose.disconnect();
}).catch(err => {
console.log('err', err);
})
1.1.5 更新数据 updateone()
& 批量更新数据updateMany()
// updateone
BookModel.updateOne({ price: 20.9 }).then(data => {
console.log('data', data);
// 8. 关闭数据库连接 项目中不会写这段
mongoose.disconnect();
}).catch(err => {
console.log('err', err);
})
// updateMany
BookModel.updateMany({ price: 19.9 }, { price: 29.9 }).then(data => {
console.log('data', data);
// 8. 关闭数据库连接 项目中不会写这段
mongoose.disconnect();
}).catch(err => {
console.log('err', err);
})
1.1.6 查询数据 findOne()
& 根据Id查询数据findById()
& 批量查询数据 find()
& 条件查询find(条件)
// findOne
BookModel.findOne({ price: 29.9 }).then(data => {
console.log('data', data);
// 8. 关闭数据库连接 项目中不会写这段
mongoose.disconnect();
}).catch(err => {
console.log('err', err);
})
// findById
BookModel.findById({ _id: '675794e424911322d51f77a6' }).then(data => {
console.log('data', data);
// 8. 关闭数据库连接 项目中不会写这段
mongoose.disconnect();
}).catch(err => {
console.log('err', err);
})
// find
BookModel.find().then(data => {
console.log('data', data);
// 8. 关闭数据库连接 项目中不会写这段
mongoose.disconnect();
}).catch(err => {
console.log('err', err);
})
// find(条件)
BookModel.find({price: '29.9'}).then(data => {
console.log('data', data);
// 8. 关闭数据库连接 项目中不会写这段
mongoose.disconnect();
}).catch(err => {
console.log('err', err);
})
1.1.7 逻辑运算 $or & $and
$and
:用于对多个表达式进行逻辑“与”(AND)运算。使用$and
时,提供的所有条件都必须为真,文档才会被包含在查询结果中。如果只是简单地列出多个查询条件而不使用 $and,它们默认也是逻辑“与”的关系。$or
:用于对多个表达式进行逻辑“或”(OR)运算。只要提供的条件数组中的任何一个条件为真,文档就会被包含在查询结果中。
简单来说,or可以类比JS中的逻辑"与"操作符 &&,and 可以类比类比为逻辑“或”操作符 ||。
注意事项:
虽然$and
和$or
在概念上可以与&&和||对应,但在实际应用中有一些细微差别需要注意:
- 默认行为:在 MonogoDB 中,如果简单的列出多个查询条件而不显式使用
$and
,他们之间默认就是“与”的关系
{ style: '励志',price:{ $lt: 30 } }
// 等价于
{$and:[{style:'励志'}, { price:{ $lt: 30} } ] }
- 复杂条件,更推荐显式使用 a n d 或者 and或者 and或者or
{$and: [ { age: { $gt: 30 } }, { age: { $lt: 60 } } ]} 表示年龄大于30岁且小于60岁。
MongoDB 中,当你执行一个查询(例如使用 $and
或 $or
等逻辑操作符),MongoDB 并不会以传统编程语言的方式对集合中的每个文档进行显式的循环检查。相反,它依赖于其内部优化机制和索引来尽可能高效地找到匹配的文档。
1.1.8 .select()
在 MongoDB 中,.find() 方法用于查询集合中的文档,而 .select() 方法用于指定返回文档中包含或排除的字段。通过这种方式,你可以控制查询结果中返回哪些字段,从而优化性能和减少数据传输量。
.select()是 Mongoose 特性,并不是 MongoDB 原生支持的方法,而是 Mongoose(一个 Node.js 中的 MongoDB 对象建模工具)提供的功能。如果你正在使用 Mongoose,那么你可以使用 .select() 来选择字段。
在 MongoDB 的查询投影中,有这样一个规则:不能同时混合使用 1 和 0 作为值(除了 _id 字段),即要么全部使用 1 来包含字段,要么全部使用 0 来排除字段,只有 _id 字段可以例外处理。
// 如果你只想获取 name 和 author 字段,并且不想要 _id 字段
db.books.find({}, { name: 1, author: 1, _id: 0 })
// 排除某些字段
db.books.find({}, { price: 0, is_hot: 0 })
// 错误演示
// MongoDB 不清楚你是想选择 name 和 author 字段,还是想排除 price 字段。在这种情况下,MongoDB 无法确定是要采用包含模式还是排除模式。
db.books.find({}, { name: 1, author: 1, price: 0 }) // 错误!
1.1.9 .sort()
.sort()
接受一个对象作为参数,该对象的键是你要排序的字段名,值为 1 标识升序(从小到大),值为-1 表示降序(从大到小),可以在.find()
方法之后链式调用.sort()
来指定排序规则。
// 单字段升序 如果价格相同的情况下,且没有提供额外的排序字段,那么这些文档的相对顺序将是不确定的(即未定义)
BookModel.find().sort({ price: 1 })
// 单字段降序
BookModel.find().sort({ price: -1 })
// 多字段排序 先根据价格升序,再根据时间降序
BookModel.find().sort({ price: 1, pub_time: -1 })
MongoDB 支持对各种类型的数据进行排序,但为了确保最佳性能,尤其是当处理大量数据时,应该尽量对数值和日期类型进行排序,并且为经常用于排序的字段创建索引。
1.2 Mongoose建议封装
新建db文件夹,封装连接操作
// db.js
module.exports = function (success, error) {
// 错误判断
if (typeof error !== 'function') {
error = () => {
console.log('连接失败');
}
}
const mongoose = require('mongoose');
// 导入配置文件
const { DBHOST, DBPORT, DBNAME } = require('../config/config');
mongoose.connect(`mongodb://${DBHOST}:${DBPORT}/${DBNAME}`);
mongoose.connection.once('open', () => {
success();
});
// 错误回调
mongoose.connection.on('error', () => {
console.log('连接失败');
})
// 关闭回调
mongoose.connection.on('close', () => {
console.log('连接关闭');
})
}
新建config文件夹,封装配置项操作
// config.js
// 配置文件
module.exports = {
DBHOST: '127.0.0.1',
DBPORT: 27017,
DBNAME: 'bilbil'
}
新建models文件夹,集合文档
// BooksModel.js
const mongoose = require('mongoose');
let BookSchema = new mongoose.Schema({
name: {
type: String,
required: true, // 必传
},
author: {
type: String,
default: '吴承恩' // 默认值
},
style: {
type: String,
enum: ['言情', '励志']
},
price: Number,
is_hot: Boolean,
tags: Array,
pub_time: Date,
});
let BookModel = mongoose.model('books', BookSchema);
module.exports = BookModel;
index.js文件
// 导入db文件
const db = require('./db/db');
const BookModel = require('./models/BooksModel');
// 调用函数
db(() => {
console.log('连接成功....');
BookModel.updateMany({ _id: '6757e85b5033ea2afd9c7b56' }, { price: 39.9 }).then(data => {
console.log('data', data);
mongoose.disconnect();
}).catch(err => {
console.log('err', err);
})
});