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}
)

in相对的修饰符是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:更多内容建议自己探索及发现,完结。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容