Mongoose学习笔记
Mongoose介绍
一、mongoose 介绍
Mongoose是在node.js异步环境下对mongodb进行便捷操作的对象模型工具。Mongoose是NodeJS的驱动,不能作为其他语言的驱动。
Mongoose有两个特点
- 通过关系型数据库的思想来设计非关系型数据库
- 基于mongodb驱动,简化操作(更方便,更灵活,更安全)
二、mongoose 安装及使用
-
安装
npm i mongoose --save
-
引入 mongoose并连接数据库
const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/test1'); 如果有账户密码需要采用下面的连接方式: 账户名:admin 密码 123456 mongoose.connect('mongodb://admin:123456@localhost:27017/test1');
-
定义Schema
数据库中的Schema,为数据库对象的集合。schema是mongoose里会用到的一种数据模式,可以理解为表结构的定义;每个schema会映射到mongodb中的一个collection,它不具备操作数据库的能力
//操作users表 定义一个Schema var UserSchema = mongoose.Schema({ //字段要和数据库的字段一一对应 userName: { type: String, required: true },//required: true 是否必填 password: String, age: Number, sex: { type: Number, default: 0 } //不传参数的话使用默认参数1 })
-
创建数据模型
定义好了Schema,接下就是生成Model。model是由schema生成的模型,可以对数据库的操作。
注意: mongoose.model 里面可以传入两个参数也可以传入三个参数
mongoose.model (参数1:模型名称(首字母大写),参数2:Schema)
mongoose.model (参数1:模型名称(首字母大写),参数2:Schema,参数3:数据库集合名称)
如果传入2个参数的话:
这个模型会和模型名称相同的复数的数据库建立连接:如通过下面方法创建模型,那么这个模型将会操作users这个集合。如果传入3个参数的话:
模型默认操作第三个参数定义的集合名称var User=mongoose.model('User', UserSchema,'user');
-
查找数据
//查询users表的数据 Users.find({}, function (err, doc) { if (err) { console.log(err); return; } console.log(doc) })
-
添加数据
//添加数据 //实例化model 通过User model创建增加的数据 var u = new Users({ userName: "张三", password: "123123", age: 22, sex: 1 }); //实例. save() u.save(function (err) { if (err) { console.log(err); return; } console.log("成功"); });
-
更新数据
//更新数据 Users.updateOne({ "_id": "5eb383a3ed09d72f5c9a082c" }, { "userName": "zhangsan" }, function (err, doc) { if (err) { return console.log(err); } console.log("成功"); });
-
删除数据
//删除数据 Users.deleteOne({ "_id": "5eb383a3ed09d72f5c9a082c" }, (err, result) => { if (err) { return console.log(err); } console.log(result) });
Mongoose预定义模式修饰符 Getters与Setters自定义修饰符
一、mongoose 预定义模式修饰符
lowercase、uppercase 、trim
mongoose提供的预定义模式修饰符,可以对我们增加的数据进行一些格式化。
var UserSchema=mongoose.Schema({
name:{
type:String,
trim:true //自动对name字段左右去空格
},
age:Number,
status:{
type:Number,
default: 1
}
})
二、Mongoose Getters 与Setters 自定义修饰符
除了mongoose内置的修饰符以外,我们还可以通过set (建议使用)修饰符在增加数据的时候对数据进行格式化。也可以通过get(不建议使用)在实例获取数据的时候对数据进行格式化
var UserSchema=mongoose.Schema({
redirect:{
type:String,
set(parmas){ //增加数据的时候对redirect字段进行处理
// parmas 可以获取redirect的值 返回的数据就是redirect在数据库实际保存的值
/*
www. baidu. com http://www.baidu.com
http://www.baidu.com http://www.baidu.com
*/
if(!parmas){
return '';
}else{
if(parmas.indexOf( 'http://')!=0 && parmas.indexOf( 'https://')!=0){
return' http:// " +parmas ;
}
return parmas;
}
}
}
})
get自定义修饰符
var UserSchema=mongoose . Schema({
name: {
type:String,
get(params){
return"111”+params;
},
age :Number,
status:{
type : Number,
default:1
}
var user=new UserModel()
user.name="张三”,
user.age=20
console.log(user.name,user.age) ;
//输出 111张三 20
Mongoose索引、扩展Mongoose Model的静态方法和实例方法
一、Mongoose索引
索引是对数据库表中一列或多列的值进行排序的一种结构,可以让我们查询数据库变得更
快。MongoDB的索引几乎与传统的关系型数据库-模-一样,这其中也包括--些基本的查询
优化技巧。
mongoose中除了以前创建索引的方式,我们也可以在定义Schema的时候指定创建索引。
var DeviceSchema = new mongoose.Schema({
sn: {
type: Number,
//唯一索引
unique: true;
},
name: {
type:String,
//普通索引
index: true;
}
});
自定义Mongoose Model的静态方法
//静态方法
UserSchema.statics.findBySn=function(sn,cb){
//通过find方法获取sn的数据 this 关键字获取当前的model
this.find({”sn":sn}, function(err,docs){
cb(err,docs)
})
}
自定义Mongoose Model的实例方法(基本不用)
UserSchema.methods.print=function(){
console.log('我是一个实例方法)
}
Mongoose数据校验
mongoose数据校验:
用户通过mongoose给mongodb数据库增加数据的时候,对数据的合法性进行的验证。
mongoose里面定义Schema:字段类型,修饰符、默认参数、数据校验都是为了数据库数据的一致性
一、Mongoose校验参数
- required: 表示这个数据必须传入
- max: 用于Number类型数据,最大值
- min: 用于Number类型数据,最小值
- enum: 枚举类型,要求数据必须满足枚举值 enum:['0', '1', '2']
- match: 增加的数据必须符合match (正则)的规则
- maxlength: 最大长度 必须用于String类型
- minlength: 最小长度 必须用于String类型
var UserSchema = new mongoose.Schema({
name:{
type:String,
required: true,
},
age: {
type: Number,
required: true,
//数字类型的最大值校验器 用在number类型上
max: 120,
//数字类型的最小值校验器
min: 0
},
status: {
type: String,
//设置字符串的可选值 注意:枚举要用在String类型上,number类型不生效
enum:['0', '1', '2']
},
phone:{
type:Number,
match: /^\d{11}$/
},
desc: {
type: String,
maxlength:20,
minlength:10
}
});
二、Mongoose自定义验证器
desc: {
type: String,
//自定义的验证器,如果通过验证返回true, 没有通过则返回false
validate: function(desc) {
return desc.length>= 10;
}
}
Mongoose中使用aggregate 聚合管道
一、MongoDB聚合管道(Aggregation Pipeline)
使用聚合管道可以对集合中的文档进行变换和组合。
实际项目:
表关联查询、数据的统计。
MongoDB中使用
db.COLLECTION_ _NAME.aggregate([{<stage>},...])
方法来构建和使用聚合管道。
mongoose中使用聚合管道
模拟数据
db.order.insert({"order_id":"1","uid":10,"trade_no":"111","all_price":100,"all_num":2})
db.order.insert({"order_id":"2","uid":7,"trade_no":"222","all_price":90,"all_num":2})
db.order.insert({"order_id":"3","uid":9,"trade_no":"333","all_price":20,"all_num":6})
db.order_item.insert({"order_id":"1","title":"商品鼠标 1","price":50,num:1})
db.order_item.insert({"order_id":"1","title":"商品键盘 2","price":50,num:1})
db.order_item.insert({"order_id":"1","title":"商品键盘 3","price":0,num:1})
db.order_item.insert({"order_id":"2","title":"牛奶","price":50,num:1})
db.order_item.insert({"order_id":"2","title":"酸奶","price":40,num:1})
db.order_item.insert({"order_id":"3","title":"矿泉水","price":2,num:5})
db.order_item.insert({"order_id":"3","title":"毛巾","price":10,num:1})
Order表
var OrderSchema = mongoose.Schema({
order_id: String, //订单ID
uid: Number, //下单用户ID
trade_no: String,//交易号
all_price: Number,//总价格
all_num: Number//总数量
})
OrderItem表
var OrderItemSchema = mongoose.Schema({
order_id: String,//订单ID
title: String, //商品名
price: Number, //价格
num: Number //数量
})
$lookup 关联查询
//order表关联Order_item查询
//只需要引入主表model
const OrderModel = require('./model/order')
OrderModel.aggregate([
{
$lookup://关联查询
{
from: "order_item",//要关联的从表
localField: "order_id",//主表ID
foreignField: "order_id",//从表ID
as: "items"//查询到的数据放到Items中
}
}
], (err, docs) => {
if (err) {
console.log(err);
return;
}
console.log(JSON.stringify(docs));
})
结果
$project 修改文档的结构
可以用来重命名,增加或者删除文档中的字段
要求查找 order 只返回文档中 trade_no 和 all_price 字段
OrderModel.aggregate([
{
$project:{
trade_no:1,
all_price:1 //只返回这两个字段
}
}
], (err, docs)=> {
if (err) {
console.log(err);
return;
}
console.log(docs)
})
结果
image$match 筛选
得到总价格>90的数据
{
$match: { "all_price": { $gte: 1000 } }// 查询总价格大于等于1000的订单
}
$group 分组
将集合中的文档进行分组,可用于统计结果。
统计每个订单的订单数量,按照订单号分组
OrderItemModel.aggregate([{
$group: {
_id: "$order_id",//按照订单号分组
total: { $sum: "$num" }//每个组的订单数量的和
}
}], (err, docs) => {
if (err) {
console.log(err);
return;
}
// console.log(docs)
console.log(JSON.stringify(docs))
})
结果
$sort 排序
1为升序,-1为降序
//排序 1为升序,-1为降序
OrderModel.aggregate([
{
$project: {
trade_no: 1,
all_price: 1
}
},
{
//1为升序,-1为降序
$sort: { "all_price": -1 }
}
], (err, docs) => {
if (err) {
console.log(err);
return;
}
console.log(docs)
})
$limit 限制 只取前几条
分页中的每页条数
OrderModel.aggregate([
{
$project: {
trade_no: 1,
all_price: 1
}
},
{
$sort: { "all_price": 1 }
},
{
$limit: 1 //只取前几条
}
], (err, docs)=> {
if (err) {
console.log(err);
return;
}
console.log(docs)
})
$skip 跳过前面多少条
分页中的 (当前页-1)*每页条数
OrderModel.aggregate([
{
$project: {
trade_no: 1,
all_price: 1
}
},
{
$sort: { "all_price": 1 }
},
{
$skip: 1 //跳过多少条 取后面剩下的
}
], function (err, docs) {
if (err) {
console.log(err);
return;
}
console.log(docs)
})
根据order_item,查询order的信息
第一种实现方式 查两次 结果拼接到一起
//查询order_ item找出商品名称是矿泉水的商品对应的订单的订单号以及订单的总价格 * /
var OrderItemModel = require('./model/order_item.js');
//第一种实现方式 查两次 结果拼接到一起
OrderItemModel.find({ "_id": "5eb3d130e8c8622f14df5d36" }, (err, docs) => {
var order_item = JSON.parse(JSON.stringify(docs));//查询出订单 转成JSON
var order_id = order_item[0].order_id;//取出订单ID用于查询客户
OrderModel.find({ "order_id": order_id }, (err, order) => {
//console.log(order);
//把order表信息拼接到order_item表的order_info字段上
order_item[0].order_info = order[0];
console.log(order_item);
})
})
结果
image第二种实现方式 表关联
//第二种实现方式 表关联
//mongoose中获取0bjectId mongoose.Types.ObjectId
OrderItemModel.aggregate([
{
$lookup:
{
from: "order", //要关联的从表
localField: "order_id",//主表ID
foreignField: "order_id",//从表ID
as: "order_info"//查询到的数据放到主表的字段中
}
}, {
$match: { _id: mongoose.Types.ObjectId('5eb3d130e8c8622f14df5d36') }
}
], (err, docs) => {
if (err) {
console.log(err);
return;
}
console.log(JSON.stringify(docs));
})
Mongoose 多表(N个表)关联查询
需求:文章(article),文章分类(articlecate),用户(user)这三个表之间的关系,一篇文章对应文章分类表中的某个类型,对应着用户表中的某个用户
image// 查询文章信息 并显示文章的分类 以及文章的作者信息
// 三个表关联查询
ArticleModel.aggregate([
{
$lookup: {
from: "articlecate", //关联的分类表
localField: "cid", //本表的cid
foreignField: "_id",//分类表的_id
as: "cate"
}
},
{
$lookup: {
from: "user",//关联的用户表
localField: "author_id",//本表的用户ID
foreignField: "_id",//关联表的用户id
as: "user"
}
}
], (err, docs) => {
console.log(JSON.stringify(docs));
})
结果
Mongoose中使用populate实现关联查询
monogodb 3.2版本以上才可用aggregate,populate任意版本都能使用
var ArticleSchema = new Schema({
title:{
type: String, unique: true
},
cid : {
type: Schema.Types.ObjectId,
ref:"ArticleCate" //外键cid和 文章分类建立关系。 model
}, /*分类 id*/
author_id:{
type: Schema.Types.ObjectId ,
ref:"User" //外键author_id和 用户表建立关系。 model
}, /*用户的id*/
author_name:{
type:String
},
descripton:String,
content : String
});
module.exports=mongoose.model('Article',ArticleSchema,'article');
//三个表关联
ArticleModel.find({}).populate('cid').populate('author_id').exec(function(err,docs){
console.log(docs);
})
mongodb数据库备份还原、数据库导入导出
在Mongodb中我们使用mongodump命令来备份MongoDB数据。该命令可以导出所有数据到指定目录中。mongodump命令可以通过参数指定导出的数据量级转存的服务器。使用mongorestore命令来恢复备份的数据。
导出:
mongodump -h dbhost -d dbname -o dbdirectory
mongodump -h 127.0.0.1 -d test1 -o C:\Users\RM-RF\Desktop\test1DB
导入:
mongorestore -h dbhost -d dbname <path>
mongorestore -h 127.0.0.1 -d test2 C:\Users\RM-RF\Desktop\test1DB\test1