mongoose 简介
Mongoos 的安装
yarn add mongoose
定义数据结构(Schema定义数据的数据结构)
const mongoose = require('mongoose')
const ProductSchema = mongoose.Schema({
id: {
type: String,
default: uuid.v1,
required: true
},
comments: [{ body: String, date: Date }],
name: String,
price: Number,
url: String
});
Schema只是定义了数据结构,而对数据的处理需要model去实现
const Product = mongoose.model('Product', ProductSchema);
module.exports = Product;
Mongoose 的 SchemaTypes(模式类型)
const egSchema = new mongoose.Schema( SchemaTypes )
1、SchemaTypes(模式类型的Type属性)
String
、Number
、Date
、Buffer
、Boolean
、Mixed
、ObjectId
(要指定类型为 ObjectId,在声明中使用Schema.Types.ObjectId
) 、Array
、Decimal128
2、required 布尔值或函数 如果值为真,为此属性添加 required 验证器。
3、default: 任何值或函数 设置此路径默认值。如果是函数,函数返回值为默认值。
4、select: 布尔值 指定 query 的默认 projections。
5、validate: 函数 adds a validator function for this property。
6、get: 函数 使用 Object.defineProperty() 定义自定义 getter。
7、set: 函数 使用 Object.defineProperty() 定义自定义 setter。
8、alias: 字符串 仅mongoose >= 4.10.0。 为该字段路径定义虚拟值 gets/sets。
索引相关
9、index: 布尔值 是否对这个属性创建索引。
10、unique: 布尔值 是否对这个属性创建唯一索引。
11、sparse: 布尔值 是否对这个属性创建稀疏索引。
connection 链接数据库 mongoose.connect(uri, options);
在db.js里面
moudle.exports = app => {
const mongoose = require('mongoose');
const dbUrl = 'mongodb://username:password@hostname:port/databasename'
mongoose.connect(dbUrl,{
useNewUrlParse: true
});
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
}
在app.js里面
const express = require('express')
const app = express()
require('../database/db.js')(app)
连接池 connection
无论是使用 mongoose.connect 或是 mongoose.createConnection 创建的连接, 都被纳入默认最大为 5 的连接池,可以通过 poolSize 选项调整:
mongoose.createConnection(uri, { poolSize: 4 });
const uri = 'mongodb://localhost/test?poolSize=4';
mongoose.createConnection(uri);
模型 models
Models 是从 Schema 编译来的构造函数。 它们的实例就代表着可以从数据库保存和读取的 documents。 从数据库创建和读取 document 的所有操作都是通过 model 进行的。
主表blog
const mongoose = require('mongoose')
const blogSchema = new mongoose.Schema({
title: {type: String}, //博客题目
abstract: {type: String}, //摘要
content: {type: String}, //文章内容
click: {type: Number},//点击量
createtime: {type: String} //消费时间
})
module.exports = mongoose.model('Blog', blogSchema)
子表label
const mongoose = require('mongoose')
const labelSchema = new mongoose.Schema({
blogid: {type: mongoose.Schema.Types.ObjectId, ref: 'blog'},//这里即为子表的外键,关联主表。 ref后的blog代表的是主表blog的Model。
label: {type: String} //标签名
});
关联查询
labelModel.find({}).populate('blogid').exec(function(err,docs){})
哪里需要模型就去哪里去引用, 新增数据
const userModel = require('../models/userModel')
const user = new userModel({
userName:'nickName',
password: 'password'
})
user.save().then(res => console.log(res))
query 查询方法
新增数据
Model.create(docs, callback) 新增数据
const model = require('../models/model');
model.create({
"productId":String,
"productName":String,
"salePrice":String,
"productImage":String,
"checked":String,
"productNum":String
}).then(res=> console.log(res));
modelData.save();
const User = require('../models/user')
const admin = new User({
username:'admin',
password:'123456',
email:'admin@admin.com'
})
admin.save(function(err,ret){})
Model.insertMany(docs, options, callback ) 插入多条数据
const blogSchema = require('../models/blog');
blogSchema.insertMany(blogs,(err) => {
console.log(err);
});
查询数据
Model.find(condition: FilterQuery, projection: any|null, options: QueryOptions, callback: Function): QueryWithHelpers<Array, DocType, THelpers, RawDocType>; 查找符合条件的内容
- 查询条件 condition
- field字段 projection 比如只查询 name 和friends 字段 ''
- projection字段 包括分页信息
await Model.find({ name: /john/I }, 'name friends', { skip: 10 })
模糊查询 使用正则表达式 let regexp = new RegExp(xxx, 'i') 来匹配需要查询的 关键词。
@Injectable()
export class AppService {
constructor(
@InjectModel(User.name) private readonly userDao: Model<userModel>,
@InjectModel(Post.name) private readonly postDao: Model<postModel>,
) { }
async test() {
let regexp = new RegExp('证书','i')
return this.postDao.find({ content: { $regex: regexp }}, null , { populate: {path: 'users'} });
}
}
如果是多个字段都要使用模糊匹配请使用$or
return await this.postDao.find({
$or:[{ title: { $regex: regexp } }, { content: { $regex: regexp } },{ author: { $regex: regexp } } ]
})
Model.findOne(condition:FilterQuery, projection:any | null , options:QueryOptions, callback:Function) QueryWithHelpers<Array, DocType, THelpers, RawDocType>;查找符合条件的内容
await Model.findOne({ type: 'iphone' }, 'name', { lean: true });
await Model.findOne({ type: 'iphone' }).select('name').lean().exec(callback);
Model.findById(id:Object|String|Number, projection: Object, options:QueryOptions, callback) 根据ID查找符合条件的内容
await Adventure.findById(id, 'name', { lean: true });
await Adventure.findById(id, 'name').lean().exec();
Model.count(conditions:FilterQuery)
await Adventure.count({ type: 'jungle' })
更新数据
更新多条数据
Model.update(conditions, docs,options,callback) 更新数据
Model.updateMany(conditions, docs, options, callback) 更新多条数据
更新单条数据
Model.findOneAndUpdate(conditions, update, options, callback) 查询并更新内容
Model.findByIdAndUpdate(id, update, options, callback ) 根据id查询并更新当前数据
Model.updateOne(conditions, options, callback ) 更新单条数据
删除数据
Model.remove()
const User = require('../models/user');
User.remove({username:'admin'},function(err,ret){})
Model.findOneAndRemove(conditions, delete, options ,callback) 查找并删除并当前数据
Model.findByIdAndRemove(conditions, delete, options ,callback) 根据id删除当前数据
中间件 Middleware
中间件 (pre 和 post 钩子) 是在异步函数执行时函数传入的控制函数。Mongoose 4.x 有四种中间件:
document 中间件
,model 中间件
,aggregate 中间件
,和query 中间件
1、document 中间件
- init
- validate
doc.validate(function (err) {
if (err) handleError(err);
else // validation passed
});
- save
product.sold = Date.now();
product.save(function (err, product) {
if (err) ..
})
- remove
product.remove(function (err, product) {
if (err) return handleError(err);
Product.findById(product._id, function (err, product) {
console.log(product) // null
})
})
2、query 中间件
- count
var countQuery = model.where({ 'color': 'black' }).count();
query.count({ color: 'black' }).count(callback)
query.count({ color: 'black' }, callback)
query.where('color', 'black').count(function (err, count) {
if (err) return handleError(err);
console.log('there are %d kittens', count);
})
- find
- findOne
- findOneAndRemove
- findOneAndUpdate
- update
aggregate 中间件
query 中间件
验证 Validators
Mongoose 有一些内建验证器。
所有 SchemaTypes
都有内建 required
验证器。required
验证器使用 checkRequired()
函数 判定这个值是否满足 required
验证器
-
Numbers
有min
和max
验证器. -
`Strings 有 enum、 match、 maxlength 和 minlength 验证器
Populate(填充) 的关联查询
Population 可以自动替换 document 中的指定字段,替换内容从其他 collection 获取。 我们可以填充(populate)单个或多个 document、单个或多个纯对象,甚至是 query 返回的一切对象。
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
现在我们创建了两个 Model。Person model 的 stories 字段设为 ObjectId数组。 ref 选项告诉 Mongoose 在填充的时候使用哪个 model,本例中为 Story model。 所有储存在此的 _id 都必须是 Story model 中 document 的 _id。
注意: ObjectId、Number、String 以及 Buffer 都可以作为 refs 使用。 但是最好还是使用 ObjectId,除非你是进阶玩家,并且有充分理由使用其他类型 作为 refs。
Population的实际运用
主表
//博客schema
var blogSchema = new mongoose.Schema({
title: {type: String}, //博客题目
abstract: {type: String}, //摘要
content: {type: String}, //文章内容
click: {type: Number},//点击量
createtime: {type: String} //消费时间
})
//创建model,第三个参数是实际表名
var blogModel = db.model("blog", blogSchema, "blog");
子表
//标签表
var labelSchema = new mongoose.Schema({
blogid: {type: mongoose.Schema.Types.ObjectId, ref: 'blog'},//这里即为子表的外键,关联主表。 ref后的blog代表的是主表blog的Model。
label: {type: String} //标签名
});
//创建model,第三个参数是实际表名
var labelModel = db.model("label", labelSchema, "label");
插入数据
//1.主表插入数据
blogModel.create({...}, function (err, doc) {
if(err) return xxx;
//2.子表插入数据。 blogid为刚插入主表的主键
labelModel.create({blogid: doc._id, label: label}, function (err, doc) {
if (err) return xxx;
})
})
关联查询
//子表关联主表查询,populate里面为子表外键
labelModel.find({}).populate('blogid').exec(function(err,docs){
})
聚合查询
//MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果; 注意_id,num_tutorial这两个字段都不能变(固定写法)
labelModel.aggregate([{$group : {_id : "$label", num_tutorial : {$sum : 1}}}],function(err,docs){
console.log(docs)
})
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)