Mongoose
1. 什么是Mongoose?
mongoose是MongoDB的数据库的对象模型工具。可以通过操作在nodeJS中对mongoose的操作实现对数据库的操作。
背景知识:
ORM:Object Relational Mapping对象关系映射。
是将对数据库的操作映射成对象的操作。(mongoose是一种ORM)
ORM优点:
1. 屏蔽数据库操作的细节
2.跨数据库平台
2. 如何实现Mongoose?
1. 创建映射对象
const mongoose = require('mongoose');
const conn = mongoose.createConnection('mongodb://localhost:27017/mydb', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// 错误监听
conn.on('error', function(err) {
console.error(err);
});
// 连接监听
conn.on('open', function() {
console.log('连接成功');
})
2. 定义Schema类
Schema类定义了字段的名称、类型、默认值
const UserSchema = new mongoose.Schema({ username: String, password: String, }, {collection: 'user'});// 第二个参数定义集合的名称
其中Schema的完整类型示例如下:
const personSchema = new mongoose.Schema({ name: {type: String, required: true}, // 字符串 binary: Buffer, // 二进制 living: Boolean, // 布尔值 birthday: {type: Date, default: Date.now}, // 日期类型 age: Number, //Number类型 // ObjectId类型 _id: Schema.Types.ObjectId, // 主键 _fk: Schema.Types.ObjectId, // 外键;其他集合的主键 //数组类型 array: [], arrOfString: [String], //字符串数组 arrOfNumber: [Number], //数字数组 arrOfDate: [Date], //日期数组 arrOfBuffer: [Buffer], //Buffer数组 arrOfBoolean: [Boolean], //布尔数组 arrOfObjectId:[Schema.Types.ObjectId] // ObjectId数组 // 内嵌文档 nested: { name: String } })
3. 创建对象模型
const User = conn.model('User', UserSchema);
4. 创建实体对象
const zhangsan = new User({username: 'zhangsan', password: 1}); // 可以改成async函数 zhangsan.save(function(err, result) { if (!err) { console.log(result) } })
5. 常见操作方法
let mongoose = require('mongoose');
let conn = mongoose.createConnection('mongodb://localhost:27017/mydb', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const UserSchema = new mongoose.Schema({
username: {type: String, required: true},
age: Number,
password: String,
createAt: {type: Date, default: Date.now}
});
const User = conn.model('User', UserSchema);
(async function() {
try{
// 插入文档
let user1 = await User.create({username: "lyra", age: 18});
let user2 = await User.create({username: "lee", age: 10});
// 更新文档
let updatedUser1 = await User.updateOne({username: 'lyra'}, {username: 'lyraLee'});
let updatedUser2 = await User.updateMany({}, {password: '123456'});
// 查询文档
let findUser1 = await User.find({age: {$gte: 10, $lt: 12}});
console.log(findUser1); // 返回一个数组
let findUser2 = await User.findOne({});
console.log(findUser2); // 返回一个对象
let findUser3 = await User.findById({_id: '5e4d62bab945ba909211d280'});
console.log(findUser3); // 返回一个对象
} catch(err) {
console.log(err);
}
})();
6. 高级查询方法
1. 带外键查询
let mongoose = require('mongoose');
let ObjectId = mongoose.Schema.Types.ObjectId;
let conn = mongoose.createConnection('mongodb://localhost:27017/mydb', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const UserSchema = new mongoose.Schema({
username: {type: String, required: true},
age: Number,
password: String,
createAt: {type: Date, default: Date.now}
}, {collection: 'user'}); //指定集合名称为user;否则默认users
const ArticleSchema = new mongoose.Schema({
title: String,
content: String,
author: {type: ObjectId, ref: 'User'} //ref表明该字段为外键;对应模型名称
});
const User = conn.model('User', UserSchema);
const Article = conn.model('Article', ArticleSchema);
// 带外键查询
(async function() {
const user = await User.create({username: 'lyra', age: 10, password: 1});
await Article.create({title: '标题', content: '内容', author: user._id})
// 查看文章的信息-包含作者的具体信息-populate的参数是外键对应的字段名称
const article = await Article.findById('5e4d6c2eb8ba3590edada416').populate('author');
console.log(article)
})()
2. 分页查询
// 分页查询 const pageSize = 3; const pageNum = 2; const users = []; for(let i=0; i< 10; i++) { users.push({username: 'lyra'+i, password: i, age: 18+i}) } (async function() { await User.create(users); User.find().sort({age: 1}).skip((pageNum-1)*pageSize).limit(pageSize).exec(function(err, result) { if(!err) { console.log(result); } }) })();
3. Mongoose模型扩展
1. 静态方法和实体方法
当某些逻辑存在重复使用的情况时,可以将其进行封装。
优点:
1. 当代码的逻辑修改时,不需要大面积修改原有代码。
2. 方法的使用者不用关心内部的实现逻辑。
扩展静态方法依据: 针对的整个集合(如:求年龄最大者);
const mongoose = require('mongoose');
const conn = mongoose.createConnection('mongodb://localhost:27017/school', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const { Schema } = mongoose;
const UserSchema = new Schema({
username: String,
password: String,
createAt: {type: Date, default: Date.now}
})
// 扩展Schema类静态方法;要位于model创建之前
UserSchema.statics.login = function(username, password) {
return this.findOne({username, password});
}
const User = conn.model('User', UserSchema);
(async function() {
await User.create({username: '1', password: '1'})
})();
// 静态方法校验
(async function(username, password) {
const result = await User.login(username, password);
console.log(result);
})('1', '1');
扩展实体方法依据: 针对的是个体(如:用户是否已经成年);
const mongoose = require('mongoose');
const conn = mongoose.createConnection('mongodb://localhost:27017/school', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const { Schema } = mongoose;
const UserSchema = new Schema({
username: String,
password: String,
createAt: {type: Date, default: Date.now}
})
// 扩展实体方法;要位于model创建之前
UserSchema.methods.login = function() {
// 从实体获取模型的方法this.model('User')
return this.model('User').findOne({username: this.username, password: this.password})
}
const User = conn.model('User', UserSchema);
(async function() {
await User.create({username: '1', password: '1'})
})();
// 实体方法校验
(async function() {
const user = new User({username: '1', password: '1'});
const result = await user.login();
console.log(result);
})()
2. 钩子-hook
在具体的操作实现前后添加一些操作的逻辑。
/** * 例如: 在注册的用户信息保存save()之前,需要将密码通过加盐算法进行加密 */ const mongoose = require('mongoose'); const crypto = require('crypto'); const conn = mongoose.createConnection('mongodb://localhost:27017/mydb', { useNewUrlParser: true, useUnifiedTopology: true }); const { Schema } = mongoose; const UserSchema = new Schema({ username: String, password: String, createAt: {type: Date, default: Date.now} }, {collection: 'user'}); // save()前添加钩子 UserSchema.pre('save', function(next) { this.password = crypto.createHmac('sha256', 'lyra').update(this.password).digest('base64'); next(); }); const User = conn.model('User', UserSchema); (async function register(username, password) { const user = new User({username, password}); user.save(); })('a', '1');
3. 虚拟属性-virtual
4. 插件-plugin
针对非自己创建的Schema,或者给定的Schema不允许直接操作时。
插件代码:
// schema是原始Schema; options是参数 module.exports = function(schema, options) { // 添加字段 schema.add({lastModified: Date}); // 钩子;每次更新前添加变更时间 schema.pre('save', function(next) { this.lastModified = new Date(); next(); }) }
逻辑代码:
const mongoose = require('mongoose');
const conn = mongoose.createConnection('mongodb://localhost:27017/mydb', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const UserSchema = new mongoose.Schema({
username: String,
password: String,
}, {collection: 'user'});
// 插件用于在保持原有Schema不变的基础上;修改Schema
let plugin = require('./plugin');
UserSchema.plugin(plugin, {index: true});
const User = conn.model('User', UserSchema);
User.create({username: 'lyra'});

浙公网安备 33010602011771号