2. Mongo基本命令操作
先来一个常用的赋值和输出命令,熟悉一下。(操作前你需要打开并链接到服务器)在命令行中输入以下代码。
var x='Hello World'
print(x)
需要注意的是这里的输出不再使用console.log(‘xxx’),而是使用print(‘xxx’),这个稍有区别。
还可以定义函数:
function fn(){
return '我是定义的函数。。。。';
}
print(fn())
基础Shell命令:
-
show dbs
:显示已有数据库,如果你刚安装好,会默认有local、admin、config,这是MongoDB的默认数据库,我们在新建库时是不允许起这些名称的。 -
use test
: 进入数据,也可以理解成为使用数据库。成功会显示:switched to db test。 -
show collections
: 显示数据库中的集合(关系型中叫表)。 -
db
:显示当前位置,也就是你当前使用的数据库名称,这个命令算是最常用的,因为你在作任何操作的时候都要先查看一下自己所在的库,以免造成操作错误。
输出结果如下(test数据库为自己创建的一个数据库,里面有cus和user两个表):
> show dbs
admin 0.000GB
config 0.000GB
db 0.000GB
local 0.000GB
test 0.000GB
> use test
switched to db test
> show collections
cus
user
> db
test
数据操作基础命令
- use db(建立数据库):use不仅可以进入一个数据库,如果你敲入的库不存在,它还可以帮你建立一个库。但是在没有集合前,它还是默认为空。
- db.集合.insert( ):新建数据集合和插入文件(数据),当集合没有时,这时候就可以新建一个集合,并向里边插入数据。Demo:db.user.insert({"name":"ddlh"})
- db.集合.find( ):查询所有数据,这条命令会列出集合下的所有数据,可以看到MongoDB是自动给我们加入了索引值的。Demo:db.user.find()
- db.集合.findOne( ):查询第一个文件数据,这里需要注意的,所有MongoDB的组合单词都使用首字母小写的驼峰式写法。Demo:db.user.findOne()
- db.集合.update({查询},{修改}):修改文件数据,第一个是查询条件,第二个是要修改成的值。这里注意的是可以多加文件数据项的,比如下面的例子。
db.user.update({"name":"ddlh"},{"name":"duan","age":"18"})
- db.集合.remove(条件):删除文件数据,注意的是要跟一个条件。
db.user.remove({"name":"李四"})
- db.集合.drop( ):删除整个集合,这个在实际工作中一定要谨慎使用,如果是程序,一定要二次确认。
db.user.drop()
- db.dropDatabase( ):删除整个数据库,在删除库时,一定要先进入数据库,然后再删除。实际工作中这个基本不用,实际工作可定需要保留数据和痕迹的。
> use user
switched to db user
>
> show dbs
admin 0.000GB
config 0.000GB
db 0.000GB
local 0.000GB
test 0.000GB
>
> db.user.insert({"name":"ddlh"})
WriteResult({ "nInserted" : 1 })
>
> db.user.find()
{ "_id" : ObjectId("5d9c5d0b5eda5a6fd0f30d71"), "name" : "ddlh" }
>
> db.user.insert({"name":"张三"}))
WriteResult({ "nInserted" : 1 })
>
> db.user.find()
{ "_id" : ObjectId("5d9c5d0b5eda5a6fd0f30d71"), "name" : "ddlh" }
{ "_id" : ObjectId("5d9c5d565eda5a6fd0f30d72"), "name" : "张三" }
>
> db.user.insert({"name":"李四"})
WriteResult({ "nInserted" : 1 })
>
> db.user.find()
{ "_id" : ObjectId("5d9c5d0b5eda5a6fd0f30d71"), "name" : "ddlh" }
{ "_id" : ObjectId("5d9c5d565eda5a6fd0f30d72"), "name" : "张三" }
{ "_id" : ObjectId("5d9c5d5e5eda5a6fd0f30d73"), "name" : "李四" }
>
> db.user.findOne()
{ "_id" : ObjectId("5d9c5d0b5eda5a6fd0f30d71"), "name" : "ddlh" }
>
>
> db.user.update({"name":"ddlh"},{"name":"duan","age":"18"})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
>
>
> db.user.find()
{ "_id" : ObjectId("5d9c5d0b5eda5a6fd0f30d71"), "name" : "duan", "age" : "18" }
{ "_id" : ObjectId("5d9c5d565eda5a6fd0f30d72"), "name" : "张三" }
{ "_id" : ObjectId("5d9c5d5e5eda5a6fd0f30d73"), "name" : "李四" }
>
>
> db.user.remove({"name":"李四"})
WriteResult({ "nRemoved" : 1 })
>
> db.user.find()
{ "_id" : ObjectId("5d9c5d0b5eda5a6fd0f30d71"), "name" : "duan", "age" : "18" }
{ "_id" : ObjectId("5d9c5d565eda5a6fd0f30d72"), "name" : "张三" }
>
>
> db.user.drop()
true
>
用js文件写mongo命令
在命令行中写mongo的命令(shell)实在是太麻烦了。尝试用JS文件来写shell命令和执行。在JS里写mongo的Shell命令大部分是相同的,只有小部分不一样。
在D:\code\mongoShell文件夹在创建一个 goTask.js 文件。使用vscode进行编辑,内容如下:
var userName="ddlh"; //声明一个登录名
var timeStamp=Date.parse(new Date()); //声明登录时的时间戳
var jsonDdatabase={"loginUnser":userName,"loginTime":timeStamp}; //组成JSON字符串
var db = connect('log'); //链接数据库
db.login.insert(jsonDdatabase); //插入数据
print('[demo]log print success'); //没有错误显示成功D
执行mongo goTask.js
输出结果如下:
D:\code\mongoShell>mongo goTask.js
MongoDB shell version v4.2.0
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("dc243992-c875-4c98-b7c1-899c4c10b107") }
MongoDB server version: 4.2.0
connecting to: mongodb://127.0.0.1:27017/log
Implicit session: session { "id" : UUID("d9f0a88c-3506-43b1-87e9-f0c7936f91ab") }
MongoDB server version: 4.2.0
[demo]log print success
大部分语句和在命令行中写法一样,需要注意的是,连接数据库时,使用var db = connect('log');
数据的批量插入
普通批量插入方法:
批量数据插入是以数组的方式进行的,我们先在命令行中敲入下面的代码,我们可以看到数据顺利插入了。
db.test.insert([ {"_id":1}, {"_id":2}, {"_id":3} ])
> db.test.insert([ {"_id":1}, {"_id":2}, {"_id":3} ])
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 3,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
> db.test.find()
{ "_id" : 1 }
{ "_id" : 2 }
{ "_id" : 3 }
>
批量插入性能测试:
先写一个for循环插入方法:
var startTime = (new Date()).getTime(); //得到开始时间
var db = connect('log'); //链接数据库
//开始循环
for(let i=0;i<1000;i++){
db.test.insert({num:i});
}
var runTime = (new Date()).getTime()-startTime;//计算时间差
print ('This run this is:'+runTime+'ms');//打印出来
我测试的时间是1191ms,这个速度虽然和电脑性能有关,但还是不太理想,1000条数据用了一秒多时间。
批量一次性插入:
var startTime = (new Date()).getTime();
var db = connect('log');
var tempArray = [] //声明一个数组
for(let i=0;i<1000;i++){ //循环向数组中放入值
tempArray.push({num:i});
}
db.test.insert(tempArray) //批量一次插入
var runTime = (new Date()).getTime()-startTime;
print ('This run this is:'+runTime+'ms');
这次用了47ms,性能远远超过循环插入。
总结:在工作中一定要照顾数据库性能,这也是你水平的提现,一个技术会了很简单,但是要作精通不那么简单。在工作中如果在循环插入和批量插入举起不定,那就选批量插入吧,它会给我们更优的性能体验。
数据修改
场景1: 只修改某条数据中的一项,(比如修改某一个人的年龄)
先模拟一个研发部成员的数据
var workmate1={
name:'炳哥',
age:18,
sex:1,
job:'前端',
skill:{
skillOne:'HTML+CSS',
SkillTwo:'JavaScript',
SkillThree:'PHP'
},
regeditTime:new Date()
}
var workmate2={
name:'军哥',
age:18,
sex:1,
job:'JAVA后端',
skill:{
skillOne:'HTML+CSS',
SkillTwo:'J2EE',
SkillThree:'PPT'
},
regeditTime:new Date()
}
var workmate3={
name:'静静',
age:20,
sex:0,
job:'UI设计',
skill:{
skillOne:'PhotoShop',
SkillTwo:'UI',
SkillThree:'Word+Excel+PPT'
},
regeditTime:new Date()
}
var db=connect('company')
var workmateArray=[workmate1,workmate2,workmate3]
db.workmate.insert(workmateArray)
print('[SUCCESS]: The data was inserted successfully.');
上面的代码,我们以文件的形式向数据库中插入了3条数据。
这时候我们需要把UI的年龄也改成18岁,需要修改这条数据我们可能会这样写。
// 修改数据 错误示例 会导致这条数据只有一个age
// db.workmate.update({name:'静静'},{age: 18})
正确的方法
可以声明一个变量,然后把要改变数据的全部信息放入变量,最后执行修改操作。:
// 修改数据 正确方法
var workmate3={
name:'静静',
age:18,
sex:0,
job:'UI设计',
skill:{
skillOne:'PhotoShop',
SkillTwo:'UI',
SkillThree:'Word+Excel+PPT'
},
regeditTime:new Date()
}
db.workmate.update({name:'静静'},workmate3)
注意:这时候静静这个用户已经不在数据库中了,需要重新载入数据再进行修改。
进阶 update修改器:
上面方法实现了数据修改正常,但是你会发现写起来非常麻烦,而且特别容易写错。为此我们要学习新知识update修改器,来解决这个问题。它可以帮助我们快速和简单的修改数据,让我们的操作更简单方便。
- $set修改器
用来修改一个指定的键值(key),这时候我们要修改某一个就非常方便了,只要一句话就可以搞定。
db.workmate.update({"name":"静静"},{"$set":{age:21}})
修改嵌套内容, 如果要修改skill.skillThree的值,可以以属性的形式进行修改:
db.workmate.update({"name":"静静"},{"$set":{"skill.skillThree":'word'}})
修改好后,我们可以用db.workmate.find()来进行查看,你会发现数据已经被修改。
- $unset用于将key删除
它的作用其实就是删除一个key值和键。一般女孩子都是不希望看到自己的年龄的,所以要求我们把年龄删除。这时候我们就可以使用$unset的形式。
db.workmate.update({"name":"静静"},{$unset:{"age":''}})
当你删除后,想加回来可以直接用set进行添加。
- $inc对数字进行计算
它是对value值的修改,但是修改的必须是数字,字符串是不起效果的。我们现在要对静静的年龄减去2岁,就可以直接用$inc来操作。
db.workmate.update({"name":"静静"},{$inc:{"age":-2}})
- multi选项
现在领导说了,你要把每个人的爱好也加入进来,但是如果你直接写会只加一个,比如下面这种形式。db.workmate.update({},{$set:{interset:[]}})
这时候你用db.workmate.find()查找,你会发现只改变了第一个数据,其他两条没有改变。这时候我们想改变就要用到multi选项。
db.workmate.update({},{$set:{interset:[]}},{multi:true})
这时候每个数据都发生了改变,multi是有ture和false两个值,true代表全部修改,false代表只修改一个(默认值)
- upsert选项
upsert是在找不到值的情况下,直接插入这条数据。比如我们这时候又来了一个新同事xiaoWang,我们这时候修改他的信息,age设置成20岁,但集合中并没有这条数据。这时候可以使用upsert选项直接添加。
db.workmate.update({name:'xiaoWang'},{$set:{age:20}},{upsert:true})
upsert也有两个值:true代表没有就添加,false代表没有不添加(默认值)。
再次进阶 update数组修改器
修改对象形式的数据
- $push追加数组/内嵌文档值
$push的功能是追加数组中的值,但我们也经常用它操作内嵌稳文档,就是{}对象型的值。先看一个追加数组值的方式,比如我们要给小王加上一个爱好(interset)为画画(draw):
db.workmate.update({name:'xiaoWang'},{$push:{interest:'draw'}})
- $each 批量追加
它可以传入一个数组,一次增加多个值进去,相当于批量操作,性能同样比循环操作要好很多,这个是需要我们注意的,工作中也要先组合成数组,然后用批量的形式进行操作。
例子:我们现在要给xiaoWang,一次加入三个爱好,唱歌(Sing),跳舞(Dance),编码(Code)。
var newInterset=["Sing","Dance","Code"];
db.workmate.update({name:"xiaoWang"},{$addToSet:{interest:{$each:newInterset}}})
- $pop 删除数组值
$pop只删除一次,并不是删除所有数组中的值。而且它有两个选项,一个是1和-1。
1:从数组末端进行删除
-1:从数组开端进行删除
例子:现在要删除xiaoWang的编码爱好(code)。
db.workmate.update({name:'xiaoWang'},{$pop:{interest:1}})
- 数组定位修改
有时候只知道修改数组的第几位,但并不知道是什么,这时候我们可以使用interest.int 的形式。
例子,比如我们现在要修改xiaoWang的第三个兴趣为编码(Code),注意这里的计数是从0开始的。
db.workmate.update({name:'xiaoWang'},{$set:{"interest.2":"Code"}})
状态返回与安全
在实际工作中,我们用db.collections.update的时候不多,在修改时我们都会用findAndModify,它可以给我们返回来一些必要的参数,让我们对修改多了很多控制力,控制力的加强也就是对安全的强化能力加强了。
应答式写入: db.runCommand();
它是数据库运行命令的执行器,执行命令首选就要使用它,因为它在Shell和驱动程序间提供了一致的接口。(几乎操作数据库的所有操作,都可以使用runCommand来执行)现在我们试着用runCommand来修改数据库,看看结果和直接用db.collections.update有什么不同。
db.workmate.update({sex:1},{$set:{money:1000}},false,true)
var resultMessage=db.runCommand({getLastError:1})
printjson(resultMessage);
上边的代码,我们修改了所有男士的数据,每个人增加了1000元钱(money),然后用db.runCommand()执行,可以看到执行结果在控制台返回了。
{
"connectionId" : 699,
"updatedExisting" : true,
"n" : 2,
"syncMillis" : 0,
"writtenTo" : null,
"err" : null,
"ok" : 1
}
- false:第一句末尾的false是upsert的简写,代表没有此条数据时不增加;
- true:true是multi的简写,代表修改所有,这两个我们在前边课程已经学过。
- getLastError:1 :表示返回功能错误,这里的参数很多,如果有兴趣请自行查找学习,这里不作过多介绍。
- printjson:表示以json对象的格式输出到控制台。
- db.listCommands( ):查看所有的Commad命令
比如我们要查看是否和数据库链接成功了,就可以使用Command命令 db.runCommand({ping:1})
返回ok:1就代表链接正常。
findAndModify:
从名字上就可以看出,findAndModify是查找并修改的意思。配置它可以在修改后给我们返回修改的结果。我们先看下面的代码:
var myModify={
findAndModify:"workmate",
query:{name:'静静'},
update:{$set:{age:16}},
new:true //更新完成,需要查看结果,如果为false不进行查看结果
}
var ResultMessage=db.runCommand(myModify);
printjson(ResultMessage)
输出结果:
{
"lastErrorObject" : {
"n" : 1,
"updatedExisting" : true
},
"value" : {
"_id" : ObjectId("5d9c78eab47ac78ecc6d3c74"),
"name" : "静静",
"sex" : 0,
"job" : "UI设计",
"skill" : {
"skillOne" : "PhotoShop",
"SkillTwo" : "UI",
"SkillThree" : "Word+Excel+PPT",
"skillThree" : "word1"
},
"regeditTime" : ISODate("2019-10-08T11:54:18.263Z"),
"age" : 16,
"interset" : [ ]
},
"ok" : 1
}
findAndModify属性值:
- query:需要查询的条件/文档
- sort: 进行排序
- remove:[boolean]是否删除查找到的文档,值填写true,可以删除。
- new:[boolean]返回更新前的文档还是更新后的文档。
- fields:需要返回的字段
- upsert:没有这个值是否增加。
findAndModify的性能是没有直接使用db.collections.update的性能好,但是在实际工作中都是使用它,毕竟要商用的程序安全性还是比较重要的。
find查找
构造数据:
我们需要构造更多的数据到集合中,这样我们才能很好的讲解查询条件,下面代码你可以直接复制进行添加。当然你也可以自己随意加一些数据到集合中,只要方便我们学习就可以了。
var workmate1={
name:'xiaoP',
age:33,
sex:1,
job:'前端',
skill:{
skillOne:'HTML+CSS',
skillTwo:'JavaScript',
skillThree:'PHP'
},
regeditTime:new Date(),
interest:[]
}
var workmate2={
name:'ShengLei',
age:31,
sex:1,
job:'JAVA后端',
skill:{
skillOne:'HTML+CSS',
skillTwo:'J2EE',
skillThree:'PPT'
},
regeditTime:new Date(),
interest:[]
}
var workmate3={
name:'MinJie',
age:18,
sex:0,
job:'UI',
skill:{
skillOne:'PhotoShop',
skillTwo:'UI',
skillThree:'PPT'
},
regeditTime:new Date(),
interest:[]
}
var workmate4={
name:'XiaoWang',
age:25,
sex:1,
job:'UI',
skill:{
skillOne:'PhotoShop',
skillTwo:'UI',
skillThree:'PPT'
},
regeditTime:new Date(),
interest:[]
}
var workmate5={
name:'LiangPeng',
age:28,
sex:1,
job:'前端',
skill:{
skillOne:'HTML+CSS',
skillTwo:'JavaScript',
},
regeditTime:new Date(),
interest:[]
}
var workmate6={
name:'HouFei',
age:25,
sex:0,
job:'前端',
skill:{
skillOne:'HTML+CSS',
skillTwo:'JavaScript',
},
regeditTime:new Date(),
interest:[]
}
var workmate7={
name:'LiuYan',
age:35,
sex:0,
job:'美工',
skill:{
skillOne:'PhotoShop',
skillTwo:'CAD',
},
regeditTime:new Date(),
interest:[]
}
var workmate8={
name:'DingLu',
age:20,
sex:0,
job:'美工',
skill:{
skillOne:'PhotoShop',
skillTwo:'CAD',
},
regeditTime:new Date(),
interest:[]
}
var workmate9={
name:'JiaPeng',
age:29,
sex:1,
job:'前端',
skill:{
skillOne:'HTML+CSS',
skillTwo:'JavaScript',
skillThree:'PHP'
},
regeditTime:new Date(),
interest:[]
}
var workmate10={
name:'LiJia',
age:26,
sex:0,
job:'前端',
skill:{
skillOne:'HTML+CSS',
skillTwo:'JavaScript',
skillThree:'PHP'
},
regeditTime:new Date(),
interest:[]
}
var db=connect('company');
var workmateArray=[workmate1,workmate2,workmate3,workmate4,workmate5,workmate6,workmate7,workmate8,workmate9,workmate10];
db.workmate.insert(workmateArray);
print('[SUCCESS]:The data was inserted successfully');
简单查找:
比如我们要查找数据中技能一为HTML+CSS的所有人。
db.workmate.find({"skill.skillOne":"HTML+CSS"})
筛选字段:
现在返回来的数据项太多,太乱,有时候我们的程序并不需要这么多选项。比如我们只需要姓名和技能就可以了。这时候我们需要写第二个参数,看下面的代码。
db.workmate.find(
{"skill.skillOne":"HTML+CSS"},
{name:true,"skill.skillOne":true}
)
你在终端会看到如下结果:
{ "_id" : ObjectId("5d9d388744beb55a978f0068"), "name" : "xiaoP", "skill" : { "s
killOne" : "HTML+CSS" } }
{ "_id" : ObjectId("5d9d388744beb55a978f0069"), "name" : "ShengLei", "skill" : {
"skillOne" : "HTML+CSS" } }
{ "_id" : ObjectId("5d9d388744beb55a978f006c"), "name" : "LiangPeng", "skill" :
{ "skillOne" : "HTML+CSS" } }
{ "_id" : ObjectId("5d9d388744beb55a978f006d"), "name" : "HouFei", "skill" : { "
skillOne" : "HTML+CSS" } }
{ "_id" : ObjectId("5d9d388744beb55a978f0070"), "name" : "JiaPeng", "skill" : {
"skillOne" : "HTML+CSS" } }
{ "_id" : ObjectId("5d9d388744beb55a978f0071"), "name" : "LiJia", "skill" : { "s
killOne" : "HTML+CSS" } }
然后你会发现多了一个ID字段,这个也不是我们想要的,这时候只要把_id:false就可以了。当然这里的false和true,也可以用0和1表示。
db.workmate.find(
{"skill.skillOne":"HTML+CSS"},
{name:true,"skill.skillOne":true,_id:false}
)
这个时候你在终端查看结果,已经是我们想要的了。
{ "name" : "xiaoP", "skill" : { "skillOne" : "HTML+CSS" } }
{ "name" : "ShengLei", "skill" : { "skillOne" : "HTML+CSS" } }
{ "name" : "LiangPeng", "skill" : { "skillOne" : "HTML+CSS" } }
{ "name" : "HouFei", "skill" : { "skillOne" : "HTML+CSS" } }
{ "name" : "JiaPeng", "skill" : { "skillOne" : "HTML+CSS" } }
{ "name" : "LiJia", "skill" : { "skillOne" : "HTML+CSS" } }
不等修饰符
如果你以前操作过关系型数据库,比如MySql,你会对>大于),<(小于),=(等于)这些东西很熟悉,但是非关系型数据库不能直接使用这些符号,稍有区别。
- 小于($lt):英文全称less-than
- 小于等于($lte):英文全称less-than-equal
- 大于($gt):英文全称greater-than
- 大于等于($gte):英文全称greater-than-equal
- 不等于($ne):英文全称not-equal
我们现在要查找一下,公司内年龄小于30大于25岁的人员。看下面的代码。
db.workmate.find(
{age:{$lte:30,$gte:25}},
{name:true,age:true,"skill.skillOne":true,_id:false}
)
日期查找
MongoDB也提供了方便的日期查找方法,现在我们要查找注册日期大于2018年1月10日的数据,我们可以这样写代码。
先声明一个日期变量,然后把使用大于符进行筛选。
var startDate= new Date('01/01/2018');
db.workmate.find(
{regeditTime:{$gt:startDate}},
{name:true,age:true,"skill.skillOne":true,_id:false}
)
find多条件查找
很多时候我们需要查询的值不只是有一个简单的条件,比如我们现在要查询一下同事中是33岁和25岁的,还比如我们要查询同事中大于30岁并且会PHP技能的。MongoDB在这方面也支持的很好,我们来学习一下。
$in修饰符
in修饰符可以轻松解决一键多值的查询情况。就如上面我们讲的例子,现在要查询同事中年龄是25岁和33岁的信息。
db.workmate.find({age:{$in:[25,33]}},
{name:1,"skill.skillOne":1,age:1,_id:0}
)
于nin,就是查询除了$in条件以外的值
$or修饰符
它用来查询多个键值的情况,就比如查询同事中大于30岁或者会做PHP的信息,$in修饰符是一个Key值。
db.workmate.find({$or:[
{age:{$gte:30}},
{"skill.skillThree":'PHP'}
]},
{name:1,"skill.skillThree":1,age:1,_id:0}
)
$and修饰符
$and用来查找几个key值都满足的情况,比如要查询同事中大于30岁并且会做PHP的信息,这时需要注意的是这两项必须全部满足。当然写法还是比较简单的。只要把上面代码中的or换成and就可以了。
db.workmate.find({$and:[
{age:{$gte:30}},
{"skill.skillThree":'PHP'}
]},
{name:1,"skill.skillThree":1,age:1,_id:0}
)
$not修饰符
它用来查询除条件之外的值,比如我们现在要查找除年龄大于20岁,小于30岁的人员信息。需要注意的是$not修饰符不能应用在条件语句中,只能在外边进行查询使用。
db.workmate.find({
age:{
$not:{
$lte:30,
$gte:20
}
}
},
{name:1,"skill.skillOne":1,age:1,_id:0}
)
find的数组查询
完善数据
以前的我们的workmate集合对数组涉及还很少,现在在数据中加入了兴趣(interest),并且给每个人加入了一些兴趣,比如有写代码,做饭,看电影…..
把之前的数据表drop掉,重新载入addData2.js
的数据,数据内容如下:
var workmate1={
name:'xiaoP',
age:33,
sex:1,
job:'前端',
skill:{
skillOne:'HTML+CSS',
skillTwo:'JavaScript',
skillThree:'PHP'
},
regeditTime:new Date(),
interest:['看电影','看书','吃美食','钓鱼','旅游']
}
var workmate2={
name:'ShengLei',
age:31,
sex:1,
job:'JAVA后端',
skill:{
skillOne:'HTML+CSS',
skillTwo:'J2EE',
skillThree:'PPT'
},
regeditTime:new Date(),
interest:['篮球','看电影','做饭']
}
var workmate3={
name:'MinJie',
age:18,
sex:0,
job:'UI',
skill:{
skillOne:'PhotoShop',
skillTwo:'UI',
skillThree:'PPT'
},
regeditTime:new Date(),
interest:['做饭','画画','看电影']
}
var workmate4={
name:'XiaoWang',
age:25,
sex:1,
job:'UI',
skill:{
skillOne:'PhotoShop',
skillTwo:'UI',
skillThree:'PPT'
},
regeditTime:new Date(),
interest:['写代码','篮球','画画']
}
var workmate5={
name:'LiangPeng',
age:28,
sex:1,
job:'前端',
skill:{
skillOne:'HTML+CSS',
skillTwo:'JavaScript',
},
regeditTime:new Date(),
interest:['玩游戏','写代码','做饭']
}
var workmate6={
name:'HouFei',
age:25,
sex:0,
job:'前端',
skill:{
skillOne:'HTML+CSS',
skillTwo:'JavaScript',
},
regeditTime:new Date(),
interest:['化妆','读书','做饭']
}
var workmate7={
name:'LiuYan',
age:35,
sex:0,
job:'美工',
skill:{
skillOne:'PhotoShop',
skillTwo:'CAD',
},
regeditTime:new Date(),
interest:['画画','聚会','看电影']
}
var workmate8={
name:'DingLu',
age:20,
sex:0,
job:'美工',
skill:{
skillOne:'PhotoShop',
skillTwo:'CAD',
},
regeditTime:new Date(),
interest:['美食','看电影','做饭']
}
var workmate9={
name:'JiaPeng',
age:29,
sex:1,
job:'前端',
skill:{
skillOne:'HTML+CSS',
skillTwo:'JavaScript',
skillThree:'PHP'
},
regeditTime:new Date(),
interest:['写代码','篮球','游泳']
}
var workmate10={
name:'LiJia',
age:26,
sex:0,
job:'前端',
skill:{
skillOne:'HTML+CSS',
skillTwo:'JavaScript',
skillThree:'PHP'
},
regeditTime:new Date(),
interest:['玩游戏','美食','篮球']
}
var db=connect('company');
var workmateArray=[workmate1,workmate2,workmate3,workmate4,workmate5,workmate6,workmate7,workmate8,workmate9,workmate10];
db.workmate.insert(workmateArray);
print('[SUCCESS]:The data was inserted successfully');
基本数组查询
比如我们想要查找兴趣爱好是“看电影”的同事,我们使用下面代码查询一下:
db.workmate.find({interest:['看电影']},
{name:1,interest:1,age:1,_id:0}
)
运行后,并没有如我们所愿得到相应的人员数据,数据为空。那问题出现在哪里?问题就在于我们写了一个中括号([]),因为加上中括号就相当于完全匹配了,所以没有得到一条符合查询条件的数据。我们去掉中括号再看看结果。
db.workmate.find({interest:'看电影'},
{name:1,interest:1,age:1,_id:0}
)
结果:
{ "name" : "xiaoP", "age" : 33, "interest" : [ "看电影", "看书", "吃美食", "钓鱼
", "旅游" ] }
{ "name" : "ShengLei", "age" : 31, "interest" : [ "篮球", "看电影", "做饭" ] }
{ "name" : "MinJie", "age" : 18, "interest" : [ "做饭", "画画", "看电影" ] }
{ "name" : "LiuYan", "age" : 35, "interest" : [ "画画", "聚会", "看电影" ] }
{ "name" : "DingLu", "age" : 20, "interest" : [ "美食", "看电影", "做饭" ] }
这就是我们在数组中查询一项的方法,这也是数组查询的最简单用法。
$all-数组多项查询
如果要查询出喜欢看电影和看书的人员信息,也就是对数组中的对象进行查询,这时候要用到一个新的查询修饰符$all。看下面的例子:
db.workmate.find(
{interest:{$all:["看电影","看书"]}},
{name:1,interest:1,age:1,_id:0}
)
结果:
{ "name" : "xiaoP", "age" : 33, "interest" : [ "看电影", "看书", "吃美食", "钓鱼
", "旅游" ] }
这时候找到了兴趣中既有看电影又有看书的人员。
$size修饰符
该修饰符可以根据数组的数量查询出结果。比如现在我们要查找兴趣的数量是5个人员信息,这时候就可以使用$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}
)
这时候就显示出了每个人兴趣的前两项,如果我们想显示兴趣的最后一项,可以直接使用slice:-1,来进行查询。
find的参数使用方法
以上所说的都是在操作find方法的第一个参数(query)和第二个参数(fields)。find还有几个常用的参数,这些参数多用在分页和排序上,下面实现一个分页的效果。
find参数:
- query:这个就是查询条件,MongoDB默认的第一个参数。
- fields:(返回内容)查询出来后显示的结果样式,可以用true和false控制是否显示。
- limit:返回的数量,后边跟数字,控制每次查询返回的结果数量。
- skip:跳过多少个显示,和limit结合可以实现分页。
- sort:排序方式,从小到大排序使用1,从大到小排序使用-1。
分页Demo:
我们把同事集合(collections)进行分页,每页显示两个,并且按照年龄从小到大的顺序排列。
db.workmate.find({},{name:true,age:true,_id:false}).limit(0).skip(2).sort({age:1});
结果:
{ "name" : "XiaoWang", "age" : 25 }
{ "name" : "HouFei", "age" : 25 }
{ "name" : "LiJia", "age" : 26 }
{ "name" : "LiangPeng", "age" : 28 }
{ "name" : "JiaPeng", "age" : 29 }
{ "name" : "ShengLei", "age" : 31 }
{ "name" : "xiaoP", "age" : 33 }
{ "name" : "LiuYan", "age" : 35 }
find如何在js文本中使用
之前的find操作都是在命令行运行的,现在我们想在通过运行js执行,可以使用下面的方法:
var db = connect("company") //进行链接对应的集合collections
var result = db.workmate.find() //声明变量result,并把查询结果赋值给result
//利用forEach进行循环输出结果。
result.forEach(function(result){
printjson(result)
})
索引
创建大量的数据(200万条)
//生成随机数
function GetRandomNum(min,max){
let range = max-min; //得到随机数区间
let rand = Math.random(); //得到随机值
return (min + Math.round(rand *range)); //最小值+随机数取整
}
//console.log(GetRandomNum(10000,99999));
//生成随机用户名
function GetRadomUserName(min,max){
let tempStringArray= "123456789qwertyuiopasdfghjklzxcvbnm".split("");//构造生成时的字母库数组
let outPuttext = ""; //最后输出的变量
//进行循环,随机生产用户名的长度,这里需要生成随机数方法的配合
for(let i=1 ;i<GetRandomNum(min,max);i++){
//随机抽取字母,拼装成需要的用户名
outPuttext=outPuttext+tempStringArray[GetRandomNum(0,tempStringArray.length)]
}
return outPuttext;
}
// console.log(GetRadomUserName(7,16))
// var startTime=(new Date()).getTime();
var db = connect('company');
db.randomInfo.drop();
var 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);
执行addData3.js代码。插入数据完成后,我们可以使用 db.randomInfo.stats() 这个命令查看数据中的数据条数。
普通查询性能
我们先制作一个普通查询,随便查找一个用户名,并计算出查询和打印的时间,因为有200万条数据,所以性能不会很高。
var startTime = new Date().getTime() //得到程序运行的开始时间
var db = connect('company') //链接数据库
var rs=db.randomInfo.find({username:"tfruhjy8k"}) //根据用户名查找用户
rs.forEach(rs=>{printjson(rs)}) //循环输出
var runTime = new Date().getTime()-startTime; //得到程序运行时间
print('[SUCCESS]This run time is:'+runTime+'ms') //打印出运行时间
上边的代码就是一个普通的查询,最后记录了时间。
建立索引
试着为用户名(username)建立索引。建立索引只需要一句话就可以了。
db.randomInfo.ensureIndex({username:1})
查看已有的索引
db.randomInfo.getIndexes()
结果:
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "company.randomInfo"
},
{
"v" : 2,
"key" : {
"username" : 1
},
"name" : "username_1",
"ns" : "company.randomInfo"
}
]
目前有两条索引,一个是id,在创建数据的时候就存在的索引,username_1是我们自己创建的索引。
然后我们在来执行以下上面的查询语句,看一下现在多少秒可以查询出来。会发现查询性能确实得到了提升。但索引这东西是要消耗硬盘和内存资源的,所以还是要根据程序需要进行建立了。
管理:用户的创建、删除与修改
安装好MongoDB时,它为我们默认开了一个最高管理权限方便我们管理数据库,我们可以用mongo链接数据库,就是这个原理。但在实际开发中并一般不能使用这个用户,因为大家都知道和最高权限的原因,安全性和可靠性都不适合,所以要对MongoDB的用户进行管理。这节课我们就学习一下MongoDB的用户管理。
创建用户:
首先要进入我们的admin库中,进入方法是直接使用use admin 就可以。进入后可以使用show collections来查看数据库中的集合。默认是只有一个集合的(system.version)。
创建用户可以用db.createUser方法来完成,里边参数还是蛮多的,代码我写在下边,然后对每一项做出了解释。
db.createUser({
user:"ddlh",
pwd:"123456",
customData:{
name:'段花花',
email:'666@163.com',
age:18,
},
roles:['read']
})
db.createUser({
user:"duan",
pwd:"123456",
customData:{
name:'段',
email:'666@163.com',
age:18,
},
roles:[
{
role:"readWrite",
db:"log"
},
'read'
]
})
内置角色:
- 数据库用户角色:read、readWrite;
- 数据库管理角色:dbAdmin、dbOwner、userAdmin;
- 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManage;
- 备份恢复角色:backup、restore;
- 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
- 超级用户角色:root
- 内部角色:__system
查找用户信息
我们直接可以使用查找的方法,查找用户信息。命令很简单:
db.system.users.find()
删除用户:
删除用户也是非常简单,直接用remove就可以删除这个用户的信息和权限。
db.system.users.remove({user:"ddlh"})
建权:
有时候我们要验证用户的用户名密码是否正确,就需要用到MongoDB提供的健全操作。也算是一种登录操作,不过MongoDB把这叫做建权。
db.auth("ddlh","123456")
如果正确返回1,如果错误返回0。(Error:Authentication failed。)
启动建权
重启MongoDB服务器,然后设置必须使用建权登录。
mongod --auth
启动后,用户登录只能用用户名和密码进行登录,原来的mongo形式链接已经不起作用了。相应的用户权限也对应妥当。实际项目中我们启动服务器必须使用建权形式。
登录
如果在配置用户之后,用户想登录,可以使用mongo的形式,不过需要配置用户名密码:
mongo -u ddlh -p 123456 127.0.0.1:27017/admin
mongo -u duan -p 123456 127.0.0.1:27017/log
这时候我们就可以用给我们的权限对数据库操作了。
管理:数据备份(mongodump)与恢复(mongorestore)
比如现在我们备份所有MongoDB里的库到D盘的databack文件夹下,就可以把命令写成这样
mongodump --host 127.0.0.1 --port 27017 --out D:/databack/
数据恢复
mongorestore --host 127.0.0.1 --port 27017 D:/databack/
tips:更多内容建议自己探索及发现,完结。