目录
一、基本命令
二、使用js编写命令,代替在cli中编写
三、修改
四、查询
五、索引
六、管理
七、mongoose
系列教程
MongoDB教程(初识篇)
一、基本命令
命令 | 功能 |
---|---|
show dbs | 显示已有数据库 |
use 库 | 进入数据库(不存在的库,立即创建) |
show collections | 显示已有集合 |
db | 显示当前所在的数据库 |
db.集合.insert() | 增(不存在的集合,立即创建,下面同理) |
db.集合.remove() | 删 |
db.集合.update() | 改 |
db.集合.find() | 查 |
db.集合.findOne() | 查,显示第一条数据 |
db.集合.drop() | 删集合 |
db.dropDatabase() | 删库 |
db.version() | 查看数据库版本 |
二、使用js编写命令,代替在cli中编写
//goTask1.js
const userName="tony" //声明一个登录名
const timeStamp=Date.parse(new Date()) //声明登录时的时间戳
const jsonDatabase={"loginUser":userName,"loginTime":timeStamp} //组成JSON字符串
const db = connect('log') //链接数据库log
db.login.insert(jsonDatabase) //插入数据
print('ok') //没有错误显示成功
//运行脚本,执行命令
mongo goTask1.js
//goTask2.js
//遇到需要插入多条数据的情况,使用数组一次性插入数据,比循环单条数据插入的性能更好
//批量插入时,每次插入的数据量,不能多于48MB
const jsonDatabase1={"loginUser":"tony","loginTime":Date.parse(new Date())}
const jsonDatabase2={"loginUser":"jenny","loginTime":Date.parse(new Date())}
const jsonDatabase3={"loginUser":"gogo","loginTime":Date.parse(new Date())}
const db = connect('log')
db.login.insert([jsonDatabase1, jsonDatabase2, jsonDatabase3])
print('ok')
//运行脚本,执行命令
mongo goTask2.js
三、修改
1、普通修改(不使用update修改器)
//普通修改,新记录填什么,数据就替换成什么
const workmate={
name:'tony',
age:33,
sex:1,
job:'前端',
skill:{
skillOne:'HTML+CSS',
skillTwo:'JavaScript',
skillThree:'PHP'
},
regeditTime:new Date(),
interest:[]
}
//原目的是修改tony的年龄,但是以下的写法,会将数据只保留age:18这一字段
db.workmate.update({name:'tony'},{age:18})
//正确做法
workmate.age=18
db.workmate.update({name:'tony'},workmate)
2、初识update修改器
(1)$set
//$set:修改部分字段
db.workmate.update({"name":"tony"},{"$set":{sex:2,age:21}})
//修改嵌套内容
db.workmate.update({"name":"tony"},{"$set":{"skill.skillThree":'word'}})
(2)$unset
//$unset:删除部分字段
db.workmate.update({"name":"tony"},{$unset:{"age":''}})
(3)$inc
//$inc:对数字进行计算,只能修改数字类型
db.workmate.update({"name":"tony"},{$inc:{"age":-2}}) //年龄减小2
(4)multi选项
//multi:true表示对所有数据,设置该字段
db.workmate.update({},{$set:{interset:[]}},{multi:true})
(5)upsert选项
//upsert:true表示若匹配的数据不存在,自动插入改数据(name),再进行数据更新(age)
db.workmate.update({name:'jenny'},{$set:{age:20}},{upsert:true})
3、update数组修改器
(1)$push
//$push:追加数组索引项
db.workmate.update({name:'tony'},{$push:{interest:'draw'}})
(2)$ne
//$ne:查找字段是否存在
//如果tony的interest里没有palyGame,我们就加入Game这个爱好
db.workmate.update({name:'tony',"interest":{$ne:'playGame'}},{$push:{interest:'playGame'}})
(3)$addToSet
//$addToSet:便捷版的$ne
//如果tony的interest里没有readBook,我们就加入readBook这个爱好
db.workmate.update({name:"tony"},{$addToSet:{interest:"readBook"}})
(4)$each
//$each:批量追加
const newInterset=["Sing","Dance","Code"]
db.workmate.update({name:"tony"},{$addToSet:{interest:{$each:newInterset}}})
(5)$pop
//$pop:删除一个数组索引项
//-1:从头部开始
//1:从尾部开始
db.workmate.update({name:'tony'},{$pop:{interest:1}})
(6)数组定位修改
//.num:定位数组的第num+1项
//修改tony的第二个interest项为YY
db.workmate.update({name:'tony'},{$set:{"interest.2":"YY"}})
4、状态返回与安全
(1)db.runCommand(应答式写入)
//false:第一句末尾的false是upsert的简写,代表没有此条数据时不增加
//true:true是multi的简写,代表修改所有,这两个我们在前边课程已经学过
//getLastError:1 :表示返回功能错误,这里的参数还有很多
//printjson:表示以json对象的格式输出到控制台
db.workmate.update({sex:1},{$set:{money:1000}},false,true)
const resultMessage=db.runCommand({getLastError:1}) //使用应答式写入
printjson(resultMessage);
(2)findAndModify
const myModify={
findAndModify:"workmate",
query:{name:'tony'},
upsert:{$set:{age:18}},
new:true //更新完成,需要查看结果,如果为false不进行查看结果
}
const ResultMessage=db.runCommand(myModify);
printjson(ResultMessage)
(3)findAndModify选项
选项 | 功能 |
---|---|
query | 需要查询的条件/文档 |
sort | 进行排序 |
remove | [boolean]是否删除查找到的文档,值填写true,可以删除。 |
new | [boolean]返回更新前的文档还是更新后的文档。 |
fields | 需要返回的字段 |
upsert | 没有这个值是否增加。 |
四、查询
1、find的不等修饰符
(1)普通查找
db.workmate.find({"skill.skillOne":"HTML+CSS"})
(2)筛选字段
//查询结果只显示该数据的name、skill.skillOne字段
db.workmate.find(
{"skill.skillOne":"HTML+CSS"},
{name:true,"skill.skillOne":true}
)
(3)不等修饰符
名称 | 含义 |
---|---|
$lt | 小于(less-than) |
$lte | 小于等于(less-than-equal) |
$gt | 大于(greater-than) |
$gte | 大于等于(greater-than-equal) |
$ne | 不等于(not-equal) |
(4)范围查找
db.workmate.find(
{age:{$lte:30,$gte:25}},
{name:true,age:true,"skill.skillOne":true,_id:false}
)
(5)日期查找
const startDate= new Date('01/01/2018');
db.workmate.find(
{regeditTime:{$gt:startDate}}, //值为Date对象
{name:true,age:true,"skill.skillOne":true,_id:false}
)
2、find的多条件查询
(1)$in
//同一字段中,挑选
db.workmate.find(
{age:{$in:[25,33]}},
{name:1,"skill.skillOne":1,age:1,_id:0}
)
(2)$or
//$or:或者
db.workmate.find(
{$or:[
{age:{$gte:30}},
{"skill.skillThree":'PHP'}
]},
{name:1,"skill.skillThree":1,age:1,_id:0}
)
(3)$and
//$and:并且
db.workmate.find(
{$and:[
{age:{$gte:30}},
{"skill.skillThree":'PHP'}
]},
{name:1,"skill.skillThree":1,age:1,_id:0}
)
(4)$not
//$not:取反
db.workmate.find({
age:{
$not:{
$lte:30,
$gte:20
}
}
},
{name:1,"skill.skillOne":1,age:1,_id:0}
)
(5)$where
db.workmate.find(
{$where:"this.age>30"},
{name:true,age:true,_id:false}
)
PS:这里的this指向的是workmate(查询集合)本身。这样我们就可以在程序中随意调用。虽然强大和灵活,但是这种查询对于数据库的压力和安全性都会变重,所以在工作中尽量减少$where修饰符的使用。
3、find的数组查询
(1)普通数组查询
//查询interest中包含画画、聚会、看电影的数据
db.workmate.find({interest:['画画','聚会','看电影']},
{name:1,interest:1,age:1,_id:0}
)
(2)$all
//条件:数组中,包含以下项
db.workmate.find(
{interest:{$all:["看电影","看书"]}},
{name:1,interest:1,age:1,_id:0}
)
(3)$in
//条件:数组中,包含其中一项
db.workmate.find(
{interest:{$in:["看电影","看书"]}},
{name:1,interest:1,age:1,_id:0}
)
(4)$size
//条件:数组长度为指定值
db.workmate.find(
{interest:{$size:5}},
{name:1,interest:1,age:1,_id:0}
)
(5)$slice
//显示数组的头两项
db.workmate.find(
{},
{name:1,interest:{$slice:2},age:1,_id:0}
)
//显示数组的尾一项
db.workmate.find(
{},
{name:1,interest:{$slice:-1},age:1,_id:0}
)
4、find的多参数实现分页
(1)find参数
名称 | 作用 |
---|---|
query | 这个就是查询条件,MongoDB默认的第一个参数 |
fields | (返回内容)查询出来后显示的结果样式,可以用true和false控制是否显示 |
limit | 返回的数量,后边跟数字,控制每次查询返回的结果数量 |
skip | 跳过多少个显示,和limit结合可以实现分页 |
sort | 排序方式,从小到大排序使用1,从大到小排序使用-1 |
(2)分页实现
db.workmate.find({},{name:true,age:true,_id:false}).limit(0).skip(2).sort({age:1});
5、find如何在js中使用
(1)使用前提
find返回的结果集,是一个数组,必须进行遍历,逐条输出。
(2)hasNext()控制游标
const db = connect("company") //进行链接对应的集合collections
const result = db.workmate.find() //声明变量result,并把查询结果赋值给result
//利用游标的hasNext()进行循环输出结果。
while(result.hasNext()){
printjson(result.next()) //用json格式打印结果
}
(3)forEach循环(更加优雅)
const db = connect("company") //进行链接对应的集合collections
const result = db.workmate.find() //声明变量result,并把查询结果赋值给result
//利用游标的hasNext()进行循环输出结果。
result.forEach(function(result){
printjson(result)
})
五、索引
1、构造百万级数据,测试索引的威力
//randomInfo.js
//生成随机数
function GetRandomNum(min,max){
const range = max-min; //得到随机数区间
const rand = Math.random(); //得到随机值
return (min + Math.round(rand *range)); //最小值+随机数取整
}
//生成随机用户名
function GetRadomUserName(min,max){
const tempStringArray= "123456789qwertyuiopasdfghjklzxcvbnm".split("");//构造生成时的字母库数组
const outPuttext = ""; //最后输出的变量
//进行循环,随机生产用户名的长度,这里需要生成随机数方法的配合
for(let i=1 ;i<GetRandomNum(min,max);i++){
//随机抽取字母,拼装成需要的用户名
outPuttext=outPuttext+tempStringArray[GetRandomNum(0,tempStringArray.length)]
}
return outPuttext;
}
//前提是,创建了company库
const db = connect('company');
const tempInfo = [];
for (let i=0;i<2000000;i++){
tempInfo.push({
username:GetRadomUserName(7,16),
regeditTime:new Date(),
randNum0:GetRandomNum(100000,999999),
randNum1:GetRandomNum(100000,999999),
randNum2:GetRandomNum(100000,999999),
randNum3:GetRandomNum(100000,999999),
randNum4:GetRandomNum(100000,999999),
randNum5:GetRandomNum(100000,999999),
randNum6:GetRandomNum(100000,999999),
randNum7:GetRandomNum(100000,999999),
randNum8:GetRandomNum(100000,999999),
randNum8:GetRandomNum(100000,999999),
})
}
db.randomInfo.insert(tempInfo);
print('ok');
//运行脚本,这个过程可能2-3分钟,根据自己的电脑配置不同,会有差别
mongo randomInfo.js
//查看集合的信息,count属性为数据量
db.randomInfo.stats()
2、索引入门
(1)作用
使用已注册索引的字段,进行数据查询,可以高度提升性能
(2)测试普通查询的性能
const startTime = new Date().getTime() //得到程序运行的开始时间
const db = connect('company') //链接数据库
const rs = db.randomInfo.find({username:"tfruhjy8k"}) //根据用户名查找用户
rs.forEach(rs=>{printjson(rs)}) //循环输出
const runTime = new Date().getTime()-startTime; //得到程序运行时间
print('[SUCCESS]This run time is:'+runTime+'ms') //打印出运行时间
(3)建立索引
//为username字段,创建索引
//大概需要一分钟左右
db.randomInfo.ensureIndex({username:1})
//查看索引注册列表
db.randomInfo.getIndexes() //此时存在两个索引,_id是mongoDB的默认索引
(4)存在复合索引的情况,hint()指定优先索引
//优先使用randNum0字段,进行查询(数字索引性能更好)
const rs = db.randomInfo.find({username:'7xwb8y3',randNum0:565509}).hint({randNum0:1});
(5)删除索引
//索引的唯一id,索引注册列表中的name即是
db.randomInfo.dropIndex('randNum0_1');
(6)索引中的小坑
- 数据不超万条时,不需要使用索引。性能的提升并不明显,而大大增加了内存和硬盘的消耗。
- 查询数据超过表数据量30%时,不要使用索引字段查询。实际证明会比不使用索引更慢,因为它大量检索了索引表和我们原表。
- 数字索引,要比字符串索引快的多,在百万级甚至千万级数据量面前,使用数字索引是个明确的选择。
- 把你经常查询的数据做成一个内嵌数据(对象型的数据),然后集体进行索引。
4、全文索引
//buildText.js
const db = connect('company')
db.info.insert({contextInfo:"I am a programmer, I love life, love family. Every day after work, I write a diary."})
db.info.insert({contextInfo:"I am a programmer, I love PlayGame, love drink. Every day after work, I playGame and drink."})
db.info.ensureIndex({contextInfo:'text'}) //使用text,代表全文索引
//searchText.js
//$text:使用全文索引,进行查询
//$search:表示搜索关键词
//1、关键词之间,使用空格隔开
//2、不需要搜索的关键词加上‘-’
//3、含空格的词句,使用转义的引号包围
const db = connect('company')
db.info.find({$text:{$search:"programmer family diary drink"}})
dbd .info.find({$text:{$search:"programmer family diary -drink"}})
db.info.find({$text:{$search:"\"love PlayGame\" drink"}})
六、管理
1、用户的创建、删除与修改
(1)创建root用户
//createRootUser.js
const db = connect('admin')
db.createUser({
user:"root",
pwd:"123456",
roles:[
{
role:"root",
db:"admin"
}
]
})
//关闭mongodb服务
db.shutdownServer()
//运行脚本
mongo createRootUser.js
内置role分类
- 数据库用户角色:read、readWrite;
- 数据库管理角色:dbAdmin、dbOwner、userAdmin;
- 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManage;
- 备份恢复角色:backup、restore;
- 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
- 超级用户角色:root
- 内部角色:__system
(2)查找用户信息(有需要再查找)
//用户操作位于admin库进行,下面同理
db.system.users.find()
(3)删除用户(有需要再删除)
db.system.users.remove({user:"tony"})
(4)重启服务器,启动权限模式
mongod --auth
(5)授权
//进入admin库,进行root用户授权操作
use admin
//如果正确返回1,如果错误返回0
//若此时不进行授权,后续将无法操作库
db.auth("root","123456")
(6)为业务使用的库创建用户
//createOtherUser.js
const db = connect('company')
db.createUser({
user:"tony",
pwd:"123456",
roles:[
{
role:"readWrite",
db:"company"
}
]
})
//运行脚本
mongo createOtherUser.js
PS:admin库设置具有root权限的用户,用于总体管理;业务库设置具有读写权限的用户,用于对业务库操作的权限控制。
2、备份和还原
(1)数据备份
//mongodump基本格式
mongodump
--host 127.0.0.1
--port 27017
--out D:/databack/backup
--collection myCollections
--db test
--username username
--password password
//备份到 D:/databack/
mongodump --host 127.0.0.1 --port 27017 --out D:/databack/
(2)数据恢复
//mongorestore基本格式
mongorestore
--host 127.0.0.1
--port 27017
--username username
--password password
<path to the backup>
//使用 D:/databack/的库,进行数据恢复
mongorestore --host 127.0.0.1 --port 27017 D:/databack/
七、mongoose
1、定义
一个简化mongodb数据库操作的工具。
2、基本操作
(1)连接数据库
const mongoose = require('mongoose')
//监听数据库的连接、断开
mongoose.connection.once('open', () => {
console.log('connect')
})
mongoose.connection.once('close', () => {
console.log('disconnect')
})
//连接数据库,域名+端口+数据库名,无端口则使用默认的27017
mongoose.connect('mongodb://127.0.0.1/company', {useNewUrlParser: true})
(2)创建Schema
//创建Schema,用于约束document
const demoSchema = mongoose.Schema({
name: String,
age: Number,
gender: {
type: Number,
default: 0
}
})
(3)创建Model
//创建model,Schema绑定在collection上
const demoModel = mongoose.model('persons', demoSchema)
(4)通过Model,操作数据
//在model中,插入数据,相当于向collection中,插入受约束的document
demoModel.create({
name: 'tony',
age: 18
}, err => {
if(!err) {
console.log('create_ok!')
}
})
(5)通过Document,操作数据
网友评论