mongoDb

MongoDB是一个基于分布式文件存储的数据库,由C++语言编写。

需要启用服务端才能使用。启用服务的命令是:Mongod,链接默认端口是27017。

ps: 启动MongoDB报错:exception in initAndListen: NonExistentPath: Data directory /data/db not found., terminating 

sudo mkdir -p /data/db

exception in initAndListen: IllegalOperation: Attempted to create a lock file on a read-only directory: /data/db, terminating

chmod 777 -R data

服务端开启后,我们可以使用命令行来链接服务端,链接命令是mongo

基本命令:

  • show dbs :  显示已有数据库,如果你刚安装好,会默认有local、admin(config),这是MongoDB的默认数据库,我们在新建库时是不允许起这些名称的。
  • use admin: 进入数据,也可以理解成为使用数据库。成功会显示:switched to db admin。
  • show collections:  显示数据库中的集合(关系型中叫表,我们要逐渐熟悉)。
  • db:  显示当前位置,也就是你当前使用的数据库名称,这个命令算是最常用的,因为你在作任何操作的时候都要先查看一下自己所在的库,以免造成操作错误。
  • 查看数据库版本命令:db.version();
  • use db(建立数据库):use不仅可以进入一个数据库,如果你敲入的库不存在,它还可以帮你建立一个库。但是在没有集合前,它还是默认为空。
  • db.集合.insert( ): 新建数据集合和插入文件(数据),当集合没有时,这时候就可以新建一个集合,并向里边插入数据。Demo:db.user.insert({“name”:”jspang”}); 批量是以数组来存储的:db.user.insert([{},{}]。注意一次插入不要超过48M
  • db.集合.find( ): 查询所有数据,这条命令会列出集合下的所有数据,可以看到MongoDB是自动给我们加入了索引值的。Demo:db.user.find()
  • db.集合.findOne( ): 查询第一个文件数据,这里需要注意的,所有MongoDB的组合单词都使用首字母小写的驼峰式写法。
  • db.集合.update({查询},{修改}): 修改文件数据,第一个是查询条件,第二个是要修改成的值。这里注意的是可以多加文件数据项的,比如下面的例子。
  • db.users.update({"name":"zhangsan"},{"name":"lisi","age":"32"})
  • db.集合.remove(条件):删除文件数据,注意的是要跟一个条件。Demo:db.user.remove({“name”:”jspang”})
  • db.集合.drop( ): 删除整个集合,这个在实际工作中一定要谨慎使用,如果是程序,一定要二次确认。
  • db.dropDatabase( ): 删除整个数据库,在删除库时,一定要先进入数据库,然后再删除。实际工作中这个基本不用,实际工作可定需要保留数据和痕迹的。 

使用js文件写mongo命令: 

test.js 

var userName="zhangsan1";    //声明一个登录名             
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');  //没有错误显示成功

执行JS文件  mongo  tes.js 插入成功。

update修改器:

$set修改器

用来修改一个指定的键值(key),这时候要修改sex和age就非常方便了。

db.workmate.update({"name":"zahngsan"},{"$set":{sex:2,age:21}})

修改好后,我们可以用db.workmate.find()来进行查看,会发现数据已经被修改。

修改嵌套内容(内嵌文档)

比如现在的UI的技能发生了变化,不会作PPT而是word作的很好,需要进行修改。skill数据是内嵌的,这时候我们可以属性的形式进行修改,skill.skillThree。具体看下面的代码。

db.workmate.update({"name":"zhangsan"},{"$set":{"skill.skillThree":'word'}})

这样就可以简单的修改内嵌文档了。

$unset用于将key删除

它的作用其实就是删除一个key值和键。一般女孩子都是不希望看到自己的年龄的,所以要求我们把年龄删除。这时候我们就可以使用$unset的形式。

db.workmate.update({"name":"zhangsan"},{$unset:{"age":''}})

当你删除后,想加回来可以直接用set进行添加。

$inc对数字进行计算

它是对value值的修改,但是修改的必须是数字,字符串是不起效果的。我们现在要对zhangsan的年龄减去2岁,就可以直接用$inc来操作。

db.workmate.update({"name":"zhangsan"},{$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是在找不到值的情况下,直接插入这条数据。比如我们这时候又来了一个新同事lisi,我们这时候修改他的信息,age设置成20岁,但集合中并没有这条数据。这时候可以使用upsert选项直接添加。

db.workmate.update({name:'lisi'},{$set:{age:20}},{upsert:true})

upsert也有两个值:true代表没有就添加,false代表没有不添加(默认值)。

push选项

$push的功能是追加 数组 中的值,但我们也经常用它操作内嵌稳文档,就是{}对象型的值。先看一个追加数组值的方式,比如我们要给lisi加上一个爱好(interset)为画画(draw):

db.workmate.update({name:'lisi'},{$push:{interest:'draw'}})

当然$push修饰符还可以为内嵌文档增加值,比如我们现在要给我们的UI,增加一项新的技能skillFour为draw,这时候我们可以操作为:

db.workmate.update({name:'zhangsan'},{$push:{"skill.skillFour":'draw'}})

$ne查找是否存在

它主要的作用是,检查一个值是否存在,如果不存在再执行操作,存在就不执行,这个很容易弄反。例子:如果lisi的爱好(interest)里没有palyGame这个值,我们就加入Game这个爱好。

db.workmate.update({name:'lisi',"interest":{$ne:'playGame'}},{$push:{interest:'Game'}})

总结:没有则修改,有则不修改。

$addToSet 升级版的$ne

它是$ne的升级版本(查找是否存在,不存在就push上去),操作起来更直观和方便,所以再工作中这个要比$en用的多。

例子:我们现在要查看lis兴趣(interest)中有没有阅读(readBook)这项,没有则加入读书(readBook)的兴趣.

db.workmate.update({name:"lisi"},{$addToSet:{interest:"readBook"}})

$each 批量追加

它可以传入一个数组,一次增加多个值进去,相当于批量操作,性能同样比循环操作要好很多,要先组合成数组,然后用批量的形式进行操作。

例子:我们现在要给lisi,一次加入三个爱好,唱歌(Sing),跳舞(Dance),编码(Code)。

var newInterset=["Sing","Dance","Code"];
db.workmate.update({name:"lisi"},{$addToSet:{interest:{$each:newInterset}}})

$pop 删除数组值

$pop只删除一次,并不是删除所有数组中的值。而且它有两个选项,一个是1和-1。

  • 1:从数组末端进行删除
  • -1:从数组开端进行删除

例子:现在要删除lisi的编码爱好(code)。

db.workmate.update({name:'lisi'},{$pop:{interest:1}})

数组定位修改

有时候只知道修改数组的第几位,但并不知道是什么,这时候我们可以使用interest.int 的形式。

例子,比如我们现在要修改lisi的第三个兴趣为编码(Code),注意这里的计数是从0开始的。

db.workmate.update({name:'lisi'},{$set:{"interest.2":"Code"}})

findAndModify(应答式操作) --状态返回和安全

db.runCommand( ):

db.workmate.update({sex:1},{$set:{money:1000}},false,true)
var resultMessage=db.runCommand({getLastError:1})
printjson(resultMessage);
  • false:第一句末尾的false是upsert的简写,代表没有此条数据时不增加;
  • true:true是multi的简写;
  • getLastError:1 :表示返回功能错误,这里的参数很多;
  • printjson:表示以json对象的格式输出到控制台;

上边的代码,我们修改了所有男士的数据,每个人增加了1000元钱(money),然后用db.runCommand()执行,可以看到执行结果在控制台返回了。

{
        "connectionId" : 1,
        "updatedExisting" : true,
        "n" : 2,
        "syncMillis" : 0,
        "writtenTo" : null,
        "err" : null,
        "ok" : 1
}
  • db.listCommands( ):查看所有的Commad命令

比如我们要查看是否和数据库链接成功了,就可以使用Command命令。

db.runCommand({ping:1})

返回ok:1就代表链接正常。

findAndModify:

从名字上就可以看出,findAndModify是查找并修改的意思。配置它可以在修改后给我们返回修改的结果。我们先看下面的代码:

var myModify={
    findAndModify:"workmate", // 集合
    query:{name:'lisi'},
    update:{$set:{age:18}},
    new:true    //更新完成,需要查看结果,如果为false不进行查看结果
}
var ResultMessage=db.runCommand(myModify);

printjson(ResultMessage)

findAndModify的性能是没有直接使用db.collections.update的性能好,但是在实际工作中都是使用它,毕竟要商用的程序安全性还是比较重要的。

findAndModify属性值:

  • query:需要查询的条件/文档
  • sort: 进行排序
  • remove:[boolean]是否删除查找到的文档,值填写true,可以删除, 和update互斥存在。
  • new:[boolean]返回更新前的文档还是更新后的文档。 
  • fields:需要返回的字段
  • upsert:没有这个值是否增加。

 find修饰符:

筛选字段

筛选字段需要写第二个参数,看下面的代码。

db.workmate.find(
    {"skill.skillOne":"HTML+CSS"},
    {name:true,"skill.skillOne":true}
)

你会在终端中看到如下结果:

{ "_id" : ObjectId("5a611350c4e36dee6008987b"), "name" : "ShengLei", "skill" : { "skillOne" : "HTML+CSS" } }
{ "_id" : ObjectId("5a611350c4e36dee6008987e"), "name" : "LiangPeng", "skill" : { "skillOne" : "HTML+CSS" } }

仔细观察查找到的数据中多了一个ID字段,这个也不是我们想要的,这时候只要把_id:false就可以了。当然这里的false和true,也可以用0和1表示。

db.workmate.find(
    {"skill.skillOne":"HTML+CSS"},
    {name:true,"skill.skillOne":true,_id:false}
)

不等修饰符

  • 小于($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月1日的数据,我们可以这样写代码。

var startDate= new Date('01/01/2018');
db.workmate.find(
    {regeditTime:{$gt:startDate}},
    {name:true,age:true,"skill.skillOne":true,_id:false}
)

多条件查询find:

$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的信息。主要区别是两个Key值。$in修饰符是一个Key值,这个需要去比较记忆。

db.workmate.find({$or:[
    {age:{$gte:30}},
    {"skill.skillThree":'PHP'}
]},
    {name:1,"skill.skillThree":1,age:1,_id:0}
)

or很好理解,就是或者的意思,我们查出来的结果也是一样的,查出了年龄大于30岁的,或者会做PHP的信息。相对应的还有$nor修饰符。

$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数组:

$all-数组多项查询

如果要查询出喜欢看电影和看书的人员信息,也就是对数组中的对象进行查询,这时候要用到一个新的查询修饰符$all。

db.workmate.find(
    {interest:{$all:["看电影","看书"]}},
    {name:1,interest:1,age:1,_id:0} 
)

这时候找到了兴趣中既有看电影又有看书的人员。

$in-数组的或者查询

用$all修饰符,是需要满足所有条件的 (有时候会跟$or弄混)。比如现在要查询爱好中有看电影的或者看书的员工信息。

db.workmate.find(
    {interest:{$in:["看电影","看书"]}},
    {name:1,interest:1,age:1,_id:0} 
)

$size-数组个数查询

$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,来进行查询。

db.workmate.find(
    {},
    {name:1,interest:{$slice:-1},age:1,_id:0} 
)

find参数:

  • query:这个就是查询条件,MongoDB默认的第一个参数。
  • fields:(返回内容)查询出来后显示的结果样式,可以用true和false控制是否显示。
  • limit:返回的数量,后边跟数字,控制每次查询返回的结果数量。
  • skip:跳过多少个显示,和limit结合可以实现分页。
  • sort:排序方式,从小到大排序使用1,从大到小排序使用-1。

分页Demo:

明白了上面这些选项,现在可以作一个最简单的分页,我们把同事集合(collections)进行分页,每页显示两个,并且按照年龄从小到大的顺序排列。

dbd .workmate.find({},{name:true,age:true,_id:false}).limit(0).skip(2).sort({age:1});

$where修饰符

它是一个非常强大的修饰符,但强大的背后也意味着有风险存在。它可以让我们在条件里使用javascript的方法来进行复杂查询。我们先来看一个最简单的例子,现在要查询年龄大于30岁的人员。

db.workmate.find(
    {$where:"this.age>30"},
    {name:true,age:true,_id:false}
)

这里的this指向的是workmate(查询集合)本身。这样我们就可以在程序中随意调用。虽然强大和灵活,但是这种查询对于数据库的压力和安全性都会变重,所以在工作中尽量减少$where修饰符的使用。

索引:

建立索引

试着为用户名(username)建立索引。建立索引只需要一句话就可以了。

db.randomInfo.ensureIndex({username:1})

查看现有索引

db.randomInfo.getIndexes()

终端的结果,现在只有一个索引值:

[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "company.randomInfo"
        }
]

那现在使用命令建立一下索引db.randomInfo.ensureIndex({uername:1}),我的电脑大概要50秒左右,建立好后我们重新使用db.randomInfo.getIndexes(),查看一下结果。

结果如下:已经变成了两条索引。

[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "company.randomInfo"
        },
        {
                "v" : 2,
                "key" : {
                        "username" : 1
                },
                "name" : "uername_1",
                "ns" : "company.randomInfo"
        }
]

然后我们查询的时间缩短到了4ms左右,查询性能提升了大概200倍左右。

总结:无论是在关系型数据库还是文档数据库,建立索引都是非常重要的。前边讲了,索引这东西是要消耗硬盘和内存资源的,所以还是要根据程序需要进行建立了。MongoDB也给我们进行了限制,只允许我们建立64个索引值。

索引中的小坑

通过实际开发和性能对比,总结了几条不用索引的情况。

  • 数据不超万条时,不需要使用索引。性能的提升并不明显,而大大增加了内存和硬盘的消耗。
  • 查询数据超过表数据量30%时,不要使用索引字段查询。实际证明会比不使用索引更慢,因为它大量检索了索引表和我们原表。
  • 数字索引,要比字符串索引快的多,在百万级甚至千万级数据量面前,使用数字索引是个明确的选择。
  • 把你经常查询的数据做成一个内嵌数据(对象型的数据),然后集体进行索引。

复合索引

复合索引就是两条以上的索引。上面已经把username字段建立了索引,我们现在把randNum0,这个字段也设置成索引。

db.randomInfo.ensureIndex({randNum0: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"
        },
        {
                "v" : 2,
                "key" : {
                        "randNum0" : 1
                },
                "name" : "randNum0_1",
                "ns" : "company.randomInfo"
        }
]

两个索引同时查询

我们同时查询两个索引的值,看看效果是怎么样的。

var startTime=new Date().getTime();
var db = connect('company');

var  rs= db.randomInfo.find({username:'7xwb8y3',randNum0:565509});

rs.forEach(rs=>{printjson(rs)});


var runTime = new Date().getTime()-startTime;
print('[Demo]this run time is '+runTime+'ms');

从性能上看并没有什么特殊的变化,查询时间还是在4ms左右。MongoDB的复合查询是按照我们的索引顺序进行查询的。就是我们用db.randomInfo.getIndexes()查询出的数组。

指定索引查询(hint)

数字的索引要比字符串的索引快,这就需要一个方法来打破索引表的查询顺序,用我们自己指定的索引优先查询,这个方法就是hint().

var  rs= db.randomInfo.find({username:'7xwb8y3',randNum0:565509}).hint({randNum0:1});

由于数据量和复杂成都还是不大,所以看不出来明显的性能提升,但是等工作中遇到大数据时,一定会得到很好的效果的。

删除索引

当索引性能不佳或起不到作用时,我们需要删除索引,删除索引的命令是dropIndex().

db.randomInfo.dropIndex('randNum0_1');//索引的唯一ID

这里需要注意的是删除时填写的值,并不是我们的字段名称(key),而是我们索引查询表中的name值

建立全文索引

 

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关键词来代表全文索引

全文索引查找 建立好了全文索引就可以查找了,查找时需要两个关键修饰符:

  • $text:表示要在全文索引中查东西。
  • $search:后边跟查找的内容。

db.info.find({$text:{$search:"programmer"}})

** 查找多个词 **

全文索引是支持多个次查找的,比如我们希望查找数据中有programmer,family,diary,drink的数据(这是或的关系),所以两条数据都会出现。

db.info.find({$text:{$search:"programmer family diary drink"}})

如果我们这时候希望不查找出来有drink这个单词的记录,我们可以使用“-”减号来取消

dbd .info.find({$text:{$search:"programmer family diary -drink"}})

转义符:

全文搜索中是支持转义符的,比如我们想搜索的是两个词(love PlayGame和drink),这时候需要使用\斜杠来转意。

db.info.find({$text:{$search:"\"love PlayGame\" drink"}})

用户的创建、管理、删除

创建用户:

首先要进入我们的admin库中,进入方法是直接使用use admin 就可以。进入后可以使用show collections来查看数据库中的集合。默认是只有一个集合的(system.version)。

创建用户可以用db.createUser方法来完成,里边参数还是蛮多的,代码我写在下边,然后对每一项做出了解释。

db.createUser({
    user:"zhangsan",
    pwd:"123456",
    customData:{
        name:'张三',
        email:'zhangsan@126.com',
        age:18,
    },
    roles:['read']
})

当然我们还可以单独配置一个数据库的权限,比如我们现在要配置compay数据库的权限为读写:

db.createUser({
    user:"zhangsan",
    pwd:"123456",
    customData:{
        name:'张三',
        email:'zhangsan@126.com',
        age:18,
    },
    roles:[
        {
            role:"readWrite",
            db:"company"
        },
        'read'
    ]
})

内置角色:

  1. 数据库用户角色:read、readWrite;
  2. 数据库管理角色:dbAdmin、dbOwner、userAdmin;
  3. 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManage;
  4. 备份恢复角色:backup、restore;
  5. 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
  6. 超级用户角色:root
  7. 内部角色:__system

查找用户信息

我们直接可以使用查找的方法,查找用户信息。命令很简单:

db.system.users.find()

删除用户:

删除名利也是非常简单,直接用remove就可以删除这个用户的信息和权限。

db.system.users.remove({user:"zhangsan"})

建权:

有时候我们要验证用户的用户名密码是否正确,就需要用到MongoDB提供的健全操作。也算是一种登录操作,不过MongoDB把这叫做建权。

db.auth("zhangsan","123456")

如果正确返回1,如果错误返回0。(Error:Authentication failed。)

启动建权

重启MongoDB服务器,然后设置必须使用建权登录。

mongod --auth

启动后,用户登录只能用用户名和密码进行登录,原来的mongo形式链接已经不起作。

备份和还原(不需要进入mongo):

mongodump
    --host: ''
    --prot: ''
    --out: ''
    --collection: ''
    --db: ''
    --username: ''
    --password: ''

// 整个数据库备份
mongodump --host 127.0.0.1 --port 27017 --out D:/backup/

还原(要进入mongo, path不需要--)

mongorestore
    --host: ''
    --prot: ''
    --username: ''
    --password: ''
   <path to the backup>

// 整个数据库还原(注意path不需要--;数据一致不会重新导入库中)
mongorestore --host 127.0.0.1 --port 27017 D:/backup/

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值