mongoose使用

407 阅读10分钟

mongodb数据库

下载地址 www.mongodb.com/try/downloa… 进入Resources 选择社区服务进行下载

配置mongoodb的环境变量

cmd 打印中mongo 查看是否安装成功

下载安装的时候 最好是不要直接安装可视化mongodb 下载会很慢

mongodb数据库使用
// cmd启动mongodb数据库
mongod --dbpath  "文件的路径" --port 端口号   开启数据库
// cmd 链接启动数据库
mongo --port 端口号

show dbs   // 展示所有的数据库
show tables // 展示对应的集合
	
use  数据库名字    // 链接到指定的数据库

db.集合名字.insert(数据)   // 向数据库的集合中填充数据 并添加集合

db.集合名字.find(数据)   // 集合查找数据(及可能多)
db.集合名字.findOne(数据) // 查找集合中的一个数据
db.集合名字.find(数据).limit(数量)  // limit(数量)限制查找数量

如果需要限制查找数据的数量可以使用limit(数量)函数
如果需要跳过指定的数据可以使用skip(数量)函数
如果需要获得查找的数据的长度可以使用count()函数

db.集合名字.remove()      删除集合中的数据(尽可能多)
db.集合名字.remove({},1) 删除集合中的一个数据

// 更新一个数据
db.集合名字.update({需要更改数据},{$set:{更改后数据}})
// 更新多个数据
db.集合名字.update(
	{需要更改数据},
	{$set:{更改后数据}},
	{multi:true}  // 更新多个数据
)

使用mongoose

使用时默认存储地址是在 安装位置的 data文件夹中

npm i mongoose  -S

const mongoose = require("mongoose")
链接本地数据库

可以通过编辑器启动 数据库

// connect 链接数据库    mongodb:数据库地址         
const mongoo =mongoose.connect("mongodb://localhost:27017/www",aptions)
// 执行之后会返回一个promise

aptions = {
    useNewUrlParser: true,
    useUnifiedTopology: true 
}
// 链接成功之后会自动提示你  输入

端口号不同的时候 使用可视化工具的时候 => 输入 mongodb://localhost:27018

链接成功
mongoo.then((res)=>{
    console.log("数据库链接成功")
}).catch((err)=>{
    
})
创建表规则
// Schema  规则
let studentSchema = new mongoose.Schema({
    name:{
        type:String,
        // 必须输入
        required:true
    },
    age:Number,  
})


/*
表规则名称
	基础类型规则
		String  字符串				:"123",
        Number  数字				 :12,
        Date    时间				 :new Date(),
        Buffer  buffer			  :new Buffer("大哥"),
        Boolean 布尔值				:true,
        Array   数组和对象都可以	 :[1,2,3]

name:{
	type: 类型

全部可用
    是否必须输入
	required :   true | false ;
	
	必须输入 不输入返回自定义报错信息
	required: [true, 'Why no bacon?'] 
	
	验证  可以不讲
	required: function() { return this.userId != null }

	default : 默认值   数组对象也可以直接返回数据 
			default  默认值可以是function 返回的默认值
	
	//自定义验证
	validate:{
      validator: function(v) {
            if(v == "WQR"){
                return false
            }
		},
        // 上面判断为false 就执行message函数
        message: '手机号码格式错误!'         
   }
   
字符串可用 

	lowercase: true   字母大写转化成字母小写
	uppercase: true   字母小写转化字母大写
	
	trim:true 	清空左右空格
	
	enum:[组合选择其中的一项]	 写入的数据必须是这其中的一项
	 
	// 字符串最大 小长度
	minlength: number
	maxlength: number
	
	
Number可用

	//数字最大最小值
	min:number
	max:number

Array 和 Object
对象嵌套   里面设置的类型无效   
	obj:{
        type:Object,
        name:String,
        age:Number,
        sex:{
            type:String,
            enum:["男","女"],
        },
    } 
	

特殊需求  
    new mongoose.Schema({
       ofString:[Number]
    })
 
使用数组包裹数据 里面的所有内容变成指定格式   不能转化就报错
  ofString:   [String],
  ofNumber:   [Number],
  ofDates:    [Date],  
  ofBuffer:   [Buffer],
  ofBoolean:  [Boolean],
 
 db.create({
    ofString: [1,2,3,"打分1",true]  全部转化成String
 })
 
可以配置对应的方法
 ofNumber:[{type:Number,max:22}]   现在不能超过22

 db.create({
    ofString: ["23","44","11","大哥"]  全部转化成String
 })
 
 无用的  
 	index: 布尔值 是否对这个属性创建索引   =>  用于升序降序
	unique: 布尔值 是否对这个属性创建唯一索引    =>  唯一值,不能重复
	
*/
子文件

子文档是嵌入在其他文档中的文档。在 Mongoose 中,这意味着您可以将模式嵌套在其他模式中。Mongoose 有两个不同的子文档概念:子文档数组和单个嵌套子文档

const childSchema = new mongoose.Schema({ name: 'string' });

const parentSchema = new mongoose.Schema({
	children: [childSchema],
    age: 'string',
});

const db = mongoose.model("qweqwe",parentSchema)

let result = db.create({
    children:[{name:"6666666"}],
    age:"123",
})

// 查找子文件对应数据  通过id查找
result.children.id(result.children[0]._id)
建表
// model 塑造                 数据集合名字   传入表规则
let MyModel = mongoose.model("modluewww",studentSchema)

// 创建数据库表
MyModel.create({
    name:"xuxin",
    age:'24'
})
初步总体
let MyModel = mongoose.model(
    // 表名
  "modluewww",
   new mongoose.Schema({
    	name:{
        	type:String,
        	// 必须输入
        	required:true
    	},
    	age:Number, 
       
		regTime:{
            type:Number,
            default : Date.now
        }
	},
    // 去除版本号
    {versionKey:false})
)

表名称是 => 复数 
单词不是复数会自动添加   

数据id名 => 表示唯一标识, 不会被重复,由一组十六进制的字符构成
versionKey:falseSchema第二参数中写上  去除版本号
数据库增删改查

集合.增 删 改 查 查找对应的集合 返回一个promisse

insertMany db.insertMany({user: 'xuxin'})

create save 都可以

// 返回值是写入的数据对象  Promise 与 await 一样的

// create( 数组 / object)
MyModel.create({
    name:"xuxin"
}).then()	

// 一次写入多个
MyModel.create(
    {name:"xuxin"}
	{name:"夏栀"}
	{name:"风息"}
	{name:"路遥"}
).then(data=>{ 
	// data 返回写入的数据对象
})	

MyModel.create(
 	[ 
     {name:"许鑫1",pas:12345},
     {name:"许鑫2",pas:12345}
    ]
)
  
let newMng = mongoose.model("dage",Mng)
// new 创建表 
let ww = new newMng({name:"qqqq"})  // 写入进去
ww.save()   // 不行就 添加await async的使用写入进去

配合使用 .then 或者 callback 或 await

findOne({}) //查找到一个      未查找到返回null 查找到返回 => 对象结构数据
findById(id) //通过id名查找   未查找到返回null 查找到返回 => 对象结构数据
find({})   // 查询多个        未查找到返回[]  查找到返回  => 数组结构数据

MyModel.find( conditions, [projection], [options], [callback] );
	conditions  查询条件
	projection  返回内容选项
	options     查询配置选项
	callback    回调函数,参数err data,可用Promise代替
    
conditions 常用查询条件,详细查询条件请参考官方文档
	{}                      基础条件块,eg:  {name:"afei"}
	
	$or $nor                或者 或者取反,eg:  {$or:[{name:"afei"},{age:"20"}]}
	
	$gt $gte $lt $lte $ne   大于 大于等于 小于 小于等于 不等于,eg:  {age:{$lt:20}}
	$in $nin                在/不在 指定的多个字段之类,eg:  {name:{$in:["afei","zhuque"]}}
	$exists                  存在某属性,eg:  {age:{$exists:true}}
	
	$size                   匹配数组长度,eg:  {arr:{$size:2}}
	$all                  数组中是否存在指定的所有项,eg:  {arr:{$all:[123,456]}}
	
	$and 				两个查询规则为true 才能返回
	
	$where               可以使用JavaScript代码或函数,eg:{$where:"this.age===18"}
	正则                    使用正则匹配,eg:  {name:/afei/}

projection  返回内容选项
	默认全部显示,
	{age:1}        只显示age属性和_id属性
	{age:1,_id:0}  只显示age属性    
    
	0 表示不隐藏   1 表示显示      
	已经隐藏的 再次设置隐藏会报错,反之同理
    find({
        $where:"this.age == 18"
    },
     {sex:0}
     )
	
options  查询配置选项
	常用skip limit sort
	{skip:2}         略过前2条数据
	{limit:5}        最多返回5条属性
	{sort:{age:1}}   按照age项升序排列  正数从小到大   负数从小到大

// 写在后面 代替回调函数
await ss.find({age:{$gt:15}}).skip(2)
await.find( tags: 'mongoose').skip(10).limit(5);


slice(number)
exists('name')

整体参数
find(
	{userName:"afeifei"},
	{userName:1,_id:0},
	{skip:2,limit:3,sort:{age:1}}
)
// 查找到 所有name为xuxin的 数据
MyModel.find({
    name:"xuxin"
}).then()

// $in 找到name为 xuxin 或 夏至的数据
// $nin 取反
MyModel.find({
    name:{$in:["xuxin" ,"夏至"]}
    // name:["xuxin" ,"夏至"]  结果是一样的
    
     // name:{$nin:["xuxi","age"]} 不取到值为xuxi age的
}).then()


// $or 查找到匹配为 name xuxin的 或者  age 18的数据
// $onr 取反
MyModel.find({
   $or:[
       {name:"xuxin"},
       {age:18}
   ]
}).then()


// $gt $gte $lt $lte $ne   大于 大于等于 小于 小于等于 不等于,eg:  {age:{$lt:20}}
find({
    age:{$gt:21}
})

// $exists                  是否存在某属性,eg:  {age:{$exists:true}}
find({
    age:{$exists:true}
})

// $size                   匹配数组长度,eg:  {arr:{$size:2}}
find({
    arr:{$size:2}   // 匹配长度为2 的数组 数据
})

// $all                  数组中是否存在指定的所有项,eg:  {arr:{$all:[123,456]}}
find({
    arr:{$all:[123,456]}   // 匹配的数据中 是不是具体这两项  有就返回
})

// this是每一项, 每一项都进行匹配
find({  
    $where:"this.age == 18"
})
可以嵌套使用

//自定义帅选  
await   find({age:14}).exec(function (err, result){
    // 数据在这里接受   不支持return 
})

$and  两个查询规则未true 才能返回
blogModel.find({ $and: [
    {meta.votes: {$gte: 50}}, 
    {meta.votes: {$lt: 100}}
]});
两个多存在

await ss.find({$and:[
    {name:"xuxin"},
    {age: 14},
]})

删除操作的时候第一个参数其实就是查询条件

需要回调函数 或者 .then 或者 await

验证

​ 删除是否能过滤为验证

// MyModel.daleteOne( conditions, [projection], [options]  只有查询有作用
MyModel.daleteOne({}) // 删除一条数据 1  返回删除几条数据deletedCount:1

MyModel.deleteMany({})  // 删除多条数据 `

//删除age值小于21的
deleteMany({
    age:{$lt:21}
})

改操作的时候第一个参数其实就是查询条件

需要回调函数 或者 .then 或者 await

// updateOne未修改  返回修改的结果     	修改后一样的只是数据进行修改 
  acknowledged: true,   是否找到
  modifiedCount: 0,     修改了几个
  upsertedId: null,
  upsertedCount: 0,
  matchedCount: 1       匹配多少数据
  
  
// update updateOne updateMany findByIdAndUpdate
// update(conditions,doc,[options],[callback])
Model.updateOne(conditions,doc,[options],[callback])

doc 要修改的内容
	{password:"456"}                     修改 password 为"456"  
	{$set:{"userInfo.test":"123"}}       修改 userInfo.test"123" 对象
	{$inc:{age:1}}                       修改 age  自增1   自减-1  值可以为任意数字
	{$unset:{age:0}}                     移除 age 属性(值随便写啥都是移除)
	
	{$push:{arr:999}}                    为 arr数组最后一项 添加 999 值
	{$push:{arr: {$each:[1,4,5,9],$slice:-5}}}  为 arr数组 添加 1 4 5 9 值,并截取倒数5个
	{$addToSet:{arr:20}}                 为 arr数组 添加一条 20 值,如果20存在,则不添加
	{$pop:{arr:1}}                       删除 arr数组 的最后一项,arr值为-1则删除第一项
	{$pull:{arr:123}}                    删除 arr数组 所有相同的123值
    									也可以删除数组中的整一项
    
//查询参数可以使用         查询配置选项作用
let result = await  db.updateMany({age:{$gt:19}},{age:18});
//修改数据
Model.updateOne({name:"xuxi"},{name:"大哥"}).then(()=>{console.log("res");})
//做出添加  前提是数据规则表中 有该类型数据
Model.updateOne({pas:1234567},{ss:"1"}).then(()=>{console.log("res");})
//修改深层对象值
{
    age:18
    name:{
    	ww : 33
    }
}
Model.updateOne({age:18},{"name.ww":1}).then(()=>{console.log("res");})

let result = await  db.updateOne({ user: '22' },{$unset:{age:1}}) 


// 在数组中使用     {$push:{数组: 数组值 }}
leaveMessagTlabe.updateOne(
    {_id:body.id},
    {
        $push:{
            children:{
                user:req.session.loginData._id,
                content:body.value,
                reUser:body.user
            }
        }
    }
)


 findByIdAndUpdate()  // 通过id选择进行修改  findByIdAndUpdate  返回跟findById一样的数据
 let result = await  db.findByIdAndUpdate("615557ec25d18a2ba2add732",{age:66})  

 updateMany() //更新所有  返回的数据和updateOne一样的
    
// 往数组中添加多个
userData.updateOne(
    {'_id:': value.result },
    {
        '$push': {
            'arrData': {
                '$each': [{"name":1},{"name":"22"}]
            }
        }
    }
);




1648652231079

// 修改数组中的对象
const qqq =async () => {
	let result = await mongoShop.updateOne(
		{mongoShopAuthor: "623f13523c3f1dfa29c152bd"},
		{
			"$set" : {
				// "mongoShopGoods.$[articleTitle]" : "66666"
				"mongoShopGoods.$[outer].articleTitle" : "666"
			},
		},
		{ 
			// 过滤数据  可以写多个
			"arrayFilters": [
		        { "outer._id": "6242c9ca9d44a1259a3fcc5b" },
			],
		}
	);
	return result
}
中间件

为Schema实例设置 pre / post 可以为后续操作设置前后钩子。

let Schema=  mongoose.Schema;
let userSchema  = new Schema({
    user:String,
    age:Number,
    arr:Object,
    obj:Array,
})
// 中间件要写在定义之前  也就是表规则插入表格中之前
userSchema.pre("find",function(next){
    console.log("find方法  执行之前,这里代码会执行");
    next();
})
userSchema.post("find",function(doc){
    console.log("find方法  执行之后,这里代码会执行");
});
let db = mongoose.model("qweqwe",userSchema);

db.find({name: 'xuxin'}).then(()=>{
    console.log("123");
})

// http://www.mongoosejs.net/docs/middleware.html 支持的
数据库

记录账号 密码数据 执行自动登录 涮新服务器不会自动退出登录

使用 express express-session mongoose

讲session数据存储到数据库中

connect-mongo  将数据存储到数据库   过期时间和前端的cookie过期时间是一样的
const connectMongo = require("connect-mongo")

在session的中间件中写
app.use(session({
    cookie:{
        
    },
    store:connectMongo.create({
        mongoUrl:"数据库地址"
    })
}))
就会自动存储到数据库中

表关联
留言表

怎么关联到是谁发布的语言

mongoose方法

// 关联的类型  type:  mongoose.Schema.Types.ObjectId,    id类型 唯一值
// 关联id类型的表  ref:"annis", 
mongoose.Schema.Types.ObjectId === Schema.Types.ObjectId

// 验证mongoose.Schema.Types.ObjectId  比字符串好用  能关联到数据直接获取

const Schema = mongoose.Schema;
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]  
author: { type: Schema.Types.ObjectId, ref: 'Person' },

 //populate关联表查询 
//populate(ref的父属性, 筛选)
//筛选    (ref的关联数据库名称           ,           0表示不需要接收)
    
// ref  关联的数据库名称  可以是数据库model(数据库名称)  或者 model返回值变量 都是可以 
    
populate("author",                            {pas:0,_id:0})
//   显示pas
populate("author","pas")
populate("author","可以不写 显示全部")  // 可以直接获取到任何位置的值  已测试

//exec 帅选完成之后 可以通过回调函数再次进行筛选
mondb1.find().populate("author",{pas:0,_id:0}).exec((re,story)=>{
    res.send(story)
})
// 取多次值
.populate("author","只显示的属性名").populate("children.user","只显示的属性名")

request.session.destroy() 销毁

链接多个数据库

createConnection(mongodb地址及名称,{ 去除 报错信息 })

const mongoose = require("mongoose")
// 链接第一个数据库
let db = mongoose.createConnection("mongodb://localhost:27018/www",{
    useNewUrlParser:true,
    useUnifiedTopology:false,
})
// 不能.then
db.on("open",()=>{
    console.log("数据库链接成功")
})
db.on("error",()=>{
    console.log("数据库链接失败")
})

let Mng =  new mongoose.Schema({
    name:String,
},{
    versionKey:false
})

let newMng = db.model("dage",Mng)
// 支持改写法
// newMng.create({name:"美少女"}).then(()=>{
//     console.log("吸入成功")})

let ww = new   newMng({name:"123123"  })
ww.save()


// 链接第二个数据库
let db1 = mongoose.createConnection("mongodb://localhost:27018/rrr",{
    useNewUrlParser:true,
    useUnifiedTopology:false,
})
db1.on("open",()=>{
    console.log("db1数据库链接成功")
})
db1.on("error",()=>{
    console.log("db1数据库链接失败")
})
let Mng1 =  new mongoose.Schema({
    name:String,
},{
    versionKey:false
})
let newMng1 = db1.model("zhen",Mng1)

//newMng1.create({name:"美少女"}).then(()=>{
//  console.log("吸入成功")})

let ww1 = new   newMng1({age:"第二个数据库"  })
ww1.save()
知识补充

查找深层对象

mongoose.model.find({"nes.name":"d"})
// nes:{ name : "d"}

nest.find({"swe.ww.ss.qwe":123})
{
    "_id":{"$oid":"6112114bcd2d4c2e8cb4fc50"},
    "nes":{"name":"d"},
    "swe":{
        "ww":{
            "ss":{
                "qwe":123
            }
        }
    },
    "__v":0
}

修改深层对象 或添加深层对象

{
    "_id":{"$oid":"61121094df4a4d1d68132c4f"},
    "nes":{
        "name":"woshinide"
    },
    "__v":0
}

nest.updateOne({"nes.name":"d"},{"nes.weer":"123"}) // 添加
nest.updateOne({"nes.name":"d"},{"nes.name":"修改的知识"})  


{
    "_id":{"$oid":"6112114bcd2d4c2e8cb4fc50"},
    "nes":{
        "name":"woshinide",
        "weer":"123"
    },
    "swe":{
        "ww":{
            "ss":{
                "qwe":123
            }
        }
    },
    "__v":0
}
表嵌套取值
const mongoose = require("mongoose")
// 注册表
let loginTable = mongoose.model("login", new mongoose.Schema({
        user:{
            type:String,
            required:true,
        },
        pass:{
            type:String,
            required:true,
        }
    },{
        versionKey:false
    })
)
// 留言表
let Schema = mongoose.Schema  // 定义特殊表格式
let leaveMessagTlabe = mongoose.model("leaveMessge",new Schema({
    // 输入的内容
    msg:{
        type:String,
        required:true,
    },
    // 表关联
    author:{
        // Schema.Types.ObjectId
        type:Schema.Types.ObjectId,
        // 关联账号的存储地址中id
        // ref  关联的数据库名称  可以是数据库model(数据库名称)  或者 model返回值变量 都是可以 
        ref:"login",  //  ref:loginTable,是变量不能使用字符串
        required:true,
    },
    children :[
        {
            user : {
                type:Schema.Types.ObjectId,
                required:true,
                ref:"login"
            },
            //内容
            content : {type: String,required: true},
            //子留言评论对象
            reUser : {type:String,required:true}
        }
    ]

},{versionKey:false})) 

// 表关联 再嵌套表关联 取值 
result = await 						     leaveMessagTlabe.find().populate("author","user").populate("children.user","user")
// populate("children.user","显示的属性")  相当于路径在此取值

// populate("数据位置")  第二参数不写获取全部 

const [result]= await leaveMessagTlabe.find().populate("children.user")  
// 也可以直接获取到数组对象中的关联值  不需要在前面点击操作author
进级