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:false 在Schema第二参数中写上 去除版本号
数据库增删改查
集合.增 删 改 查 查找对应的集合 返回一个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"}]
}
}
}
);
// 修改数组中的对象
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
进级