最近作项目利用mongo记录的日志作数据统计。着了非关系型数据库的迷,因而乎买了本《MongoDB实战》学习了一番。记录一下学习笔记,共享之。html
我在本身的Linux服务器上装了最新版的Mongo。记录一下安装连接还有一个遇到的问题。java
Linux安装mongo https://blog.51cto.com/13641879/2141129mysql
我想看数据库状态的时候遇到了一个权限问题正则表达式
> db.serverStatus() { "ok" : 0, "errmsg" : "not authorized on admin to execute command { serverStatus: 1.0, lsid: { id: UUID(\"bbda7ede-9e92-492b-ae2f-f0f641fba261\") }, $db: \"admin\" }", "code" : 13, "codeName" : "Unauthorized" }
解决方法:https://www.cnblogs.com/alexzhang92/p/10479105.html算法
若是看了上面那个解决方法,咱们再次进入mongo shell模式(以admin)须要输入一下命令:sql
mongo -u 'admin' -p '123' --authenticationDatabase 'admin'mongodb
mysql | mongo | 解释 |
---|---|---|
database | database | 数据库 |
table | collection | 集合 |
row | document | 文档 |
column | field | 域 |
Mongo储存数据都是以BSON格式的,相似于JSON,以下:shell
{ "_id": ObjectId("5d399bb2b52d6dc8a4ff6b42"), "name": "pjjlt" }
若是不指定主键,会默认生成一个_id(长度一共12字节),生成规则:4个字节的时间戳+3个字节的机器Id+2个字节的进程Id+3个字节的随机数数据库
> show dbs #查看全部数据库和使用状况 admin 0.000GB config 0.000GB local 0.000GB > use pjjlt #切换到pjjlt库,发现没有建立之 switched to db pjjlt > db #查看当前在操做哪一个数据库 pjjlt > db.myCollection.insert({"name":"pjjlt"}) #在pjjlt库的myCollection集合(没有此集合,建立之)插入一条数据 WriteResult({ "nInserted" : 1 }) > show collections #查看本库(pjjlt)下全部集合 myCollection > db.myCollection.find() #查询某集合数据 { "_id" : ObjectId("5d399bb2b52d6dc8a4ff6b42"), "name" : "pjjlt" } #篇幅缘由,不演示下面操做了,直接说解释 >db.myCollection.drop() #删除某集合 >db.dropDatabase() #删除某数据库 >db.serverStatus() #查看服务器状态信息(查看引擎就在这边看,能够看到mongo4的默认引擎已是wiredtiger了) >db.stats() #当前数据库下简单信息 能够查看本库下有多少集合 >db.myCollection.stats() #查看某集合的基础信息 >db.runCommand() #能够执行某个function()方法 >db.help() #查看数据库层面全部操做 >db.myCollection.help() #查看集合层面全部操做 >db.listCommands() #列举数据库全部命令
数据插入,可分为insert和save方法。具体全部方法,能够先输入一段代码,再按两下tab键查看。数组
#两下TAB键,看下有如下方法。insert能够实现后面两个方法的功能,即插入一条或多条 > db.myCollection.insert db.myCollection.insert( db.myCollection.insertMany( db.myCollection.insertOne( #插入一条记录 > db.myCollection.insert({"name":"haha"}) WriteResult({ "nInserted" : 1 }) #插入多条记录,输出的信息会更加详细 > db.myCollection.insert([{"name":"hehe"},{"name":"heihei"}]) BulkWriteResult({ "writeErrors" : [ ], "writeConcernErrors" : [ ], "nInserted" : 2, "nUpserted" : 0, "nMatched" : 0, "nModified" : 0, "nRemoved" : 0, "upserted" : [ ] }) #看下myCollection集合下有多少数据 > db.myCollection.count() 4 #再看下内容,_id是自动生成的主键。 > db.myCollection.find() { "_id" : ObjectId("5d399bb2b52d6dc8a4ff6b42"), "name" : "pjjlt" } { "_id" : ObjectId("5d3a6bafd40e94efd747de7b"), "name" : "haha" } { "_id" : ObjectId("5d3a6c3fd40e94efd747de7c"), "name" : "hehe" } { "_id" : ObjectId("5d3a6c3fd40e94efd747de7d"), "name" : "heihei" } #看一下save的插入功能,save能够指定_id #若是有_id存在则更新,没有就是插入,功能相似insert > db.myCollection.save({"name":"save0"}) WriteResult({ "nInserted" : 1 }) > db.myCollection.save([{"name":"save1"},{"name":"save2"}]) BulkWriteResult({ "writeErrors" : [ ], "writeConcernErrors" : [ ], "nInserted" : 2, "nUpserted" : 0, "nMatched" : 0, "nModified" : 0, "nRemoved" : 0, "upserted" : [ ] }) > db.myCollection.find() { "_id" : ObjectId("5d399bb2b52d6dc8a4ff6b42"), "name" : "pjjlt" } { "_id" : ObjectId("5d3a6bafd40e94efd747de7b"), "name" : "haha" } { "_id" : ObjectId("5d3a6c3fd40e94efd747de7c"), "name" : "hehe" } { "_id" : ObjectId("5d3a6c3fd40e94efd747de7d"), "name" : "heihei" } { "_id" : ObjectId("5d3a927fb4d620841817e434"), "name" : "save0" } { "_id" : ObjectId("5d3a92a2b4d620841817e436"), "name" : "save1" } { "_id" : ObjectId("5d3a92a2b4d620841817e437"), "name" : "save2" }
数据修改有命令save和update,其中update有具备局部更新和替换更新的功能
#先看下save方法,指定_id,进行修改 > db.myCollection.save({"_id":ObjectId("5d3a92a2b4d620841817e437"),"name":"save3"}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.myCollection.find() { "_id" : ObjectId("5d399bb2b52d6dc8a4ff6b42"), "name" : "pjjlt" } { "_id" : ObjectId("5d3a6bafd40e94efd747de7b"), "name" : "haha" } { "_id" : ObjectId("5d3a6c3fd40e94efd747de7c"), "name" : "hehe" } { "_id" : ObjectId("5d3a6c3fd40e94efd747de7d"), "name" : "heihei" } { "_id" : ObjectId("5d3a927fb4d620841817e434"), "name" : "save0" } { "_id" : ObjectId("5d3a92a2b4d620841817e436"), "name" : "save1" } { "_id" : ObjectId("5d3a92a2b4d620841817e437"), "name" : "save3" } #而后看update方法,同insert同样,update能够实现后面两个方法 > db.myCollection.update db.myCollection.update( db.myCollection.updateMany( db.myCollection.updateOne(
看下update语法
db.collection.update( <query>, #update的查询条件,相似sql update语句where后面的部分 <update>, #update的对象和一些更新的操做符等,也能够理解为sql update语句set后面的 { upsert: <boolean>, #可选,这个参数的意思是,若是不存在update的记录,是否插入objNew,true为插入,默认是false,不插入 multi: <boolean>, #可选,mongodb 默认是false,只更新找到的第一条记录,若是这个参数为true,就把按条件查出来多条记录所有更新 writeConcern: <document> #可选,抛出异常的级别 } )
接着回到例子中,为了说明方便,咱们新建一个新的集合user
#给新的集合建一个新的文档 > db.user.insert({"username":"pjjlt","age":25}) WriteResult({ "nInserted" : 1 }) > db.user.find().pretty() { "_id" : ObjectId("5d3aa1fcb4d620841817e438"), "username" : "pjjlt", "age" : 25 } # ok,把pjjlt的年龄改为18,使用了关键字$set,待会会演示不使用这个关键字的效果 > db.user.update({"_id" : ObjectId("5d3aa1fcb4d620841817e438")},{$set:{"age":18}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.user.find().pretty() { "_id" : ObjectId("5d3aa1fcb4d620841817e438"), "username" : "pjjlt", "age" : 18 } #若是使用了$set是局部更新,若是不使用,就是替换更新,为了区分,咱们已跟新新的域city为例 > db.user.update({"_id" : ObjectId("5d3aa1fcb4d620841817e438")},{"city":"SJZ"}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.user.find().pretty() { "_id" : ObjectId("5d3aa1fcb4d620841817e438"), "city" : "SJZ" } #发现原始数据也没了,由于被所有替换了
数据删除可使用deleteMany、deleteOne、remove
# 两下Tab > db.user.delete db.user.deleteMany( db.user.deleteOne( # 删除没数据了 > db.user.deleteOne({"_id" : ObjectId("5d3aa1fcb4d620841817e438")}) { "acknowledged" : true, "deletedCount" : 1 } > db.user.find().pretty() > # 再增长几条数据 > db.user.find() { "_id" : ObjectId("5d3ab2f8b4d620841817e439"), "username" : "pjjlt", "age" : 25 } { "_id" : ObjectId("5d3ab2fdb4d620841817e43a"), "username" : "pjjlt1", "age" : 25 } { "_id" : ObjectId("5d3ab302b4d620841817e43b"), "username" : "pjjlt2", "age" : 25 } { "_id" : ObjectId("5d3ab322b4d620841817e43c"), "username" : "pjjlt3", "age" : 18 }
remove语法
db.collection.remove( <query>, #可选,查询条件 { justOne: <boolean>, #可选,设置为true或者1,表示只删除一个文档,设置为false,表示删除全部匹配的文档,默认为false writeConcern: <document> #可选,抛出异常的级别 } )
再回到例子删除一下。须要手动释放磁盘空间
> db.user.remove({"age" : 25}) WriteResult({ "nRemoved" : 3 }) > db.user.find() { "_id" : ObjectId("5d3ab322b4d620841817e43c"), "username" : "pjjlt3", "age" : 18 } #手动释放磁盘空间 > db.repairDatabase() { "ok" : 1 }
几乎大部分的业务都和查询有关。
运算符 | 描述 |
---|---|
$lt | 小于 |
$gt | 大于 |
$lte | 小于等于 |
$gte | 大于等于 |
准备一个大数据集合,往numbers集合里面添加1000个数字
#前面那三个点是自动生成的,对代码没有影响,请忽略 > for(i=0;i<1000;i++){ ... db.numbers.save({num:i}); ... } WriteResult({ "nInserted" : 1 }) #测试一个$lt,其余雷同 > db.numbers.find({"num":{$lt:5}}) { "_id" : ObjectId("5d3ac7b7b4d620841817e43d"), "num" : 0 } { "_id" : ObjectId("5d3ac7b8b4d620841817e43e"), "num" : 1 } { "_id" : ObjectId("5d3ac7b8b4d620841817e43f"), "num" : 2 } { "_id" : ObjectId("5d3ac7b8b4d620841817e440"), "num" : 3 } { "_id" : ObjectId("5d3ac7b8b4d620841817e441"), "num" : 4 }
运算符 | 描述 |
---|---|
$in | 若是任意参数引用集合里,则匹配 |
$all | 若是全部参数再引用集合里且被使用在包含数组的文档中,则匹配 |
$nin | 若是没有参数在引用集合里,则匹配 |
#插入一条记录 > db.tools.insert({tools:["AAA","BBB","CCC","DDD","EEE"]}) WriteResult({ "nInserted" : 1 }) #查看一下 > db.tools.find() { "_id" : ObjectId("5d3ad78eb4d620841817e825"), "tools" : [ "AAA", "BBB", "CCC", "DDD", "EEE" ] } #经过$in搜出来了 > db.tools.find({tools:{ ... $in:["AAA","FFF","ZZZ"] ... } ... }) { "_id" : ObjectId("5d3ad78eb4d620841817e825"), "tools" : [ "AAA", "BBB", "CCC", "DDD", "EEE" ] } #$all搜索测试 > db.tools.find({tools:{ $all:["AAA","FFF","ZZZ"] } }) > db.tools.find({tools:{ $all:["AAA","BBB"] } }) { "_id" : ObjectId("5d3ad78eb4d620841817e825"), "tools" : [ "AAA", "BBB", "CCC", "DDD", "EEE" ] } #$nin搜索测试 > db.tools.find({tools:{ $nin:["AAA","BBB"] } }) > db.tools.find({tools:{ $nin:["ZZZ","YYY"] } }) { "_id" : ObjectId("5d3ad78eb4d620841817e825"), "tools" : [ "AAA", "BBB", "CCC", "DDD", "EEE" ] }
运算符 | 描述 |
---|---|
$ne | 不匹配参数 |
$not | 不匹配结果 |
$or | 有一个条件匹配就成立 |
$nor | 全部条件都不匹配 |
$and | 全部条件都匹配 |
$exists | 判断元素是否存在 |
#接着上面的例子,使用$ne > db.tools.find({tools:{$ne:"AAA"}}) > db.tools.find({tools:{$ne:"ZZZ"}}) { "_id" : ObjectId("5d3ad78eb4d620841817e825"), "tools" : [ "AAA", "BBB", "CCC", "DDD", "EEE" ] } #$not 看就就像条件取反 > db.tools.find({tools:{$not:{$in:["AAA"]}}}) > db.tools.find({tools:{$not:{$in:["ZZZ"]}}}) { "_id" : ObjectId("5d3ad78eb4d620841817e825"), "tools" : [ "AAA", "BBB", "CCC", "DDD", "EEE" ] } #为了演示下面的功能,添加新域给刚才那个文档 > db.tools.update({"_id" : ObjectId("5d3ad78eb4d620841817e825")},{$set:{"city":"SJZ"}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.tools.find().pretty() { "_id" : ObjectId("5d3ad78eb4d620841817e825"), "tools" : [ "AAA", "BBB", "CCC", "DDD", "EEE" ], "city" : "SJZ" } #$or > db.tools.find( {$or:[ {tools:{$in:["AAA"]}}, {"city":"BJ"} ]} ) { "_id" : ObjectId("5d3ad78eb4d620841817e825"), "tools" : [ "AAA", "BBB", "CCC", "DDD", "EEE" ], "city" : "SJZ" } #$nor 全部条件都不匹配 > db.tools.find( {$nor:[ {tools:{$in:["ZZZ"]}}, {"city":"BJ"} ]} ) { "_id" : ObjectId("5d3ad78eb4d620841817e825"), "tools" : [ "AAA", "BBB", "CCC", "DDD", "EEE" ], "city" : "SJZ" } #$and > db.tools.find( {$and:[ {tools:{$in:["AAA"]}}, {"city":"BJ"} ]} ) > db.tools.find( {$and:[ {tools:{$in:["AAA"]}}, {"city":"SJZ"} ]} ) { "_id" : ObjectId("5d3ad78eb4d620841817e825"), "tools" : [ "AAA", "BBB", "CCC", "DDD", "EEE" ], "city" : "SJZ" } #$exists # tools集合是否存在tools域 > db.tools.find({"tools":{$exists:true}}) { "_id" : ObjectId("5d3ad78eb4d620841817e825"), "tools" : [ "AAA", "BBB", "CCC", "DDD", "EEE" ], "city" : "SJZ" } # tools集合是否不存在tools域 > db.tools.find({"tools":{$exists:false}}) >
运算符 | 描述 |
---|---|
$elemMatch | 若是提供的全部词语在相同的子文档中,则匹配 |
$size | 若是子文档数组大小与提供的文本值相同,则匹配 |
#在新的集合里面插入新的文档 > db.products.insert({addresses:[{name:"home",city:"sjz"},{name:"work",city:"bj"}]}) WriteResult({ "nInserted" : 1 }) > db.products.find().pretty() { "_id" : ObjectId("5d3ae3763d2312bc3a0be84c"), "addresses" : [ { "name" : "home", "city" : "sjz" }, { "name" : "work", "city" : "bj" } ] } #$elemMatch 须要子文档的哦 > db.products.find({addresses:{$elemMatch:{"name":"home","city":"sjz"}}}) { "_id" : ObjectId("5d3ae3763d2312bc3a0be84c"), "addresses" : [ { "name" : "home", "city" : "sjz" }, { "name" : "work", "city" : "bj" } ] } #size > db.products.find({"addresses":{$size:1}}) > db.products.find({"addresses":{$size:2}}) { "_id" : ObjectId("5d3ae3763d2312bc3a0be84c"), "addresses" : [ { "name" : "home", "city" : "sjz" }, { "name" : "work", "city" : "bj" } ] }
运算符 | 描述 |
---|---|
$sort | 排序 1 正序;-1 倒叙 |
$limit | 显示多少条 |
$skip | 跳过多少数据 |
注意和MySQL同样,skip操做大数的时候会很慢,须要提早缩小范围
#使用numbers这个集合 > db.numbers.find().sort({"num":-1}).skip(33).limit(9) { "_id" : ObjectId("5d3ac7b8b4d620841817e803"), "num" : 966 } { "_id" : ObjectId("5d3ac7b8b4d620841817e802"), "num" : 965 } { "_id" : ObjectId("5d3ac7b8b4d620841817e801"), "num" : 964 } { "_id" : ObjectId("5d3ac7b8b4d620841817e800"), "num" : 963 } { "_id" : ObjectId("5d3ac7b8b4d620841817e7ff"), "num" : 962 } { "_id" : ObjectId("5d3ac7b8b4d620841817e7fe"), "num" : 961 } { "_id" : ObjectId("5d3ac7b8b4d620841817e7fd"), "num" : 960 } { "_id" : ObjectId("5d3ac7b8b4d620841817e7fc"), "num" : 959 } { "_id" : ObjectId("5d3ac7b8b4d620841817e7fb"), "num" : 958 }
运算符 | 描述 |
---|---|
$where | 执行任意JavaScript来选择文档 |
$regex | 匹配正则表达式 |
$mod[(quatient),(result)] | 若是元素除以除数符合结果则匹配 |
$type | 若是元素的类型符合指定的BSON类型则匹配 |
$text | 容许在创建文本索引的字段上执行文本搜索 |
null | 不是关键词,不用加$,只是看一下使用 |
#只演示下 mod 和 regex #接着用刚才numbers那个集合 > db.numbers.find({"num":{$mod:[200,3]}}) { "_id" : ObjectId("5d3ac7b8b4d620841817e440"), "num" : 3 } { "_id" : ObjectId("5d3ac7b8b4d620841817e508"), "num" : 203 } { "_id" : ObjectId("5d3ac7b8b4d620841817e5d0"), "num" : 403 } { "_id" : ObjectId("5d3ac7b8b4d620841817e698"), "num" : 603 } { "_id" : ObjectId("5d3ac7b8b4d620841817e760"), "num" : 803 } #使用刚才user集合,搜索全部username以p开头的文档 > db.user.find({"username":{$regex:/^p.*/}}) { "_id" : ObjectId("5d3ab322b4d620841817e43c"), "username" : "pjjlt3", "age" : 18 } #null的使用,搜索出没有这个域的文档,或者这个域为null > db.user.find({"username":null}) > db.user.find({"username111":null}) { "_id" : ObjectId("5d3ab322b4d620841817e43c"), "username" : "pjjlt3", "age" : 18 }
能够把聚合框架理解成SQL中的GROUP BY。为了调用聚合框架就要定义一个管道。聚合管道里的每一步输出做为下一步的输入。相似于流的概念。
运算符 | 描述 |
---|---|
$project | 指定输出文档里的字段(项目) |
$match | 选择要处理的字段,与find()相似 |
$limit | 限制传递给下一步文档数量 |
$skip | 跳过必定数量的文档 |
$unwind | 拓展数组,为每个数组入口生成一个输出文档 |
$group | 根据key来分组文档 |
$skip | 排序文档 |
$geoNear | 选择某个地理位置附近的文档 |
$out | 把管道的结果写入某集合 |
$redact | 控制特定数据的访问 |
以上不少命令符与上面查询命令符功能相同,$geoNear(这个貌似颇有趣,相似于图论中迪杰斯特拉、弗洛伊德那些算法,能够计算坐标点之间的物理距离)和$redact先不过多的讨论。$limit、$skip、$skip也过于简单,上面演示过了,这里再也不重复。看一下这些命令和关系型数据库SQL的类比
SQL命令 | 聚合命令操做符 |
---|---|
SELECT | $project $group functions : $sum,$min,$avg,etc. |
FROM | db.collectionName.aggregate(...) |
JOIN | $unwind |
WHERE | $match |
GROUP BY | $group |
HAVING | $match |
可是集合命令操做符没必要按照以上顺序进行书写,好比能够先写$match进行条件筛选,而后进行其余操做(其实,也每每建议这么作,毕竟第一步就把大部分没用的数据过滤了)
#为了方便说明,新建一个集合 > db.score.find() { "_id" : ObjectId("5d3bac2d78b22e869eb2fd26"), "name" : "pjjlt", "age" : 25, "city" : "sjz" } { "_id" : ObjectId("5d3bac5878b22e869eb2fd27"), "name" : "qex", "age" : 112, "city" : "london" } { "_id" : ObjectId("5d3bad9078b22e869eb2fd28"), "name" : "haha", "age" : 24, "city" : "sjz" } { "_id" : ObjectId("5d3bada078b22e869eb2fd29"), "name" : "heihei", "age" : 25, "city" : "bj" } #验证$match和$project > db.score.aggregate([ ... {$match:{age:{$lt:100}}}, //条件过滤 ... {$project:{"_id":0}} //不显示主键 ... ]) { "name" : "pjjlt", "age" : 25, "city" : "sjz" } { "name" : "haha", "age" : 24, "city" : "sjz" } { "name" : "heihei", "age" : 25, "city" : "bj" } #接下来分组显示每一个城市的平均年龄 > db.score.aggregate([ {$group:{_id:"$city",avgAge:{$avg:"$age"}}} ]) { "_id" : "bj", "avgAge" : 25 } { "_id" : "london", "avgAge" : 112 } { "_id" : "sjz", "avgAge" : 24.5 }
对于$group,对于原始数据如city、age,进行显示的时候前面也须要加上$,如$city、$age,不然显示为null
另外展现一下$group中可使用的命令
命令 | 描述 |
---|---|
$addToSet | 为组里惟一的值建立一个数组 |
$first | 组里第一个值,只有前缀$sort才有意义 |
$last | 组里最后一个值,只有前缀$sort才有意义 |
$max | 组里某个字段的最大值 |
$min | 组里某个字段的最小值 |
$avg | 某个字段的平均值 |
$push | 返回组内全部值的数组。不去重复值 |
$sum | 求组内全部值的和 |
#回来接着展现$out字符,而且$out字符相似于Java8中的流收集器,必须放最后执行 > db.score.aggregate([ {$group:{_id:"$city",avgAge:{$avg:"$age"}}} ,{$out:'aResult'}]) #删除一下变量中的数据 > db.aResult.find() { "_id" : "bj", "avgAge" : 25 } { "_id" : "london", "avgAge" : 112 } { "_id" : "sjz", "avgAge" : 24.5 } #最后是$unwind,接着用上次那个tools集合 > db.tools.find() { "_id" : ObjectId("5d3ad78eb4d620841817e825"), "tools" : [ "AAA", "BBB", "CCC", "DDD", "EEE" ], "city" : "SJZ" } > db.tools.aggregate([ ... {$project:{"_id":0}}, ... {$unwind:"$tools"} ... ]) { "tools" : "AAA", "city" : "SJZ" } { "tools" : "BBB", "city" : "SJZ" } { "tools" : "CCC", "city" : "SJZ" } { "tools" : "DDD", "city" : "SJZ" } { "tools" : "EEE", "city" : "SJZ" }
同关系型数据库同样,在project的时候,能够对数据进行进一步加工,可选函数有concat、toLower、toUpper这种字符串函数;add、mod、multiply这种算数运算函数;日期运算符;逻辑运算符;集合操做符等。之后有空在总结。
mongo在事务处理方面不如mysql。好比两个不一样线程update的时候(+1操做)可能会出现数据被覆盖的现象。特别介绍一个具备原子性的操做findAndModify(),总找到到修改提交是一个原子事件,期间其余线程查询该数据会被拒绝。
固然为了保护数据,在业务代码层面(好比java)能够考虑加锁。
> db.score.find({"name":"qex"}) { "_id" : ObjectId("5d3bac5878b22e869eb2fd27"), "name" : "qex", "age" : 112, "city" : "london" } #修改qex的年龄 > db.score.findAndModify({ ... query:{"name":"qex"}, ... update:{ $inc:{"age":+3}} ... }) { "_id" : ObjectId("5d3bac5878b22e869eb2fd27"), "name" : "qex", "age" : 112, "city" : "london" } > db.score.find({"name":"qex"}) { "_id" : ObjectId("5d3bac5878b22e869eb2fd27"), "name" : "qex", "age" : 115, "city" : "london" }
总结一下更新操做符
操做符 | 描述 |
---|---|
$inc | 根据给定的值更改数字 |
$set | 设置字段为给定的值 |
$unset | 取消设置字段 |
$rename | 重命名字段给定的值 |
$setOnInsert | 在upsert中,插入时设置字段 |
$bit | 只执行按位更新字段 |
$ | 根据查询选择器定位要更新的子文档 |
$push | 添加值到数组中 |
$addToSet | 添加值到数组中,重复了也不处理 |
$pop | 从数组中删除第一个或者最后一个值 |
$pull | 从数组中删除匹配查询条件的值 |
$pullAll | 从数组中删除多个值 |
$each | 从push和addToSet一块儿使用来操做多个值 |
$slice | 从push和each一块儿使用来缩小更新后数组的大小 |
$sort | 从push和each、slice一块儿使用来排序数组中的子文档 |
$isolated | 隔离其余操做,不容许其余操做交叉更新多个文档 |
确保该数据在该集合只有一份,好比说主键,格式:
> db.user.createIndex({username:1},{unique:true}) { "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 }
稀疏索引能够保证某些文档不包含这个属性,就不会被筛选出来。例如经过电话号码建索引,可是集合中有的文档电话号码是null,在建立索引的时候就不会把这些文档考虑进来。
> db.user.createIndex({username:1},{sparse:true})
索引字段是个数字,好比tools集合中的tools域,这意味着针对这些数组任意值在索引上的查询都会定位到文档上
哈希索引的好处是可让索引上的入口是均匀分布的
db.user.createIndex({username:'hashed'})
查询某个地点附近的文档,基于经纬度来储存每一个文档。
固然从引用域的数量来讲还能够分为单键索引和复合索引,和mysql的行为相似。
使用createIndex()。因为创建索引的时候,数据量大会致使系统长时间等待,因此要能够指定后台索引(因为须要大量数据,我没实验),还有离线索引等等。
db.user.createIndex({username:'hashed'},{background:true})
索引反复操做可能会在内存中产生大量碎片,可使用命令进行碎片整理(索引新建之)
> db.user.reIndex() { "nIndexesWas" : 2, "nIndexes" : 2, "indexes" : [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "pjjlt.user" }, { "v" : 2, "unique" : true, "key" : { "username" : 1 }, "name" : "username_1", "ns" : "pjjlt.user" } ], "ok" : 1 }
查看某个集合的索引使用getIndexes()
> db.user.getIndexes() [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "pjjlt.user" }, { "v" : 2, "unique" : true, "key" : { "username" : 1 }, "name" : "username_1", "ns" : "pjjlt.user" } ]
> db.user.dropIndex("username_1") #名字能够在查看索引的时候找到 { "nIndexesWas" : 2, "ok" : 1 }
主要有两种:MMAPV1和WiredTiger.在2.6版本以前只有MMAPV1,在3.0以后有了WiredTiger,可是默认仍是MMAPV1。本篇使用的是4版本,已经默认是WiredTiger引擎了。相对于说MMAPV1,WiredTiger使用磁盘空间小得多,只须要将近七、8分之一的空间。记得从旧版本的mongo升级,导数据,原来20G的数据最后只有个位数(具体几G忘了),吓一跳,还担忧会丢数据,原来是引擎变了。同时锁的颗粒度从数据库到文档级别,并发性能提高很多。总之,新的引擎占资源小,性能还高。
复制:复制是跨多个Mongo服务器(节点)分布和维护数据的方法。MongoDB能够把数据从一个节点复制到其余节点并在修改时进行同步。这种类型的复制是经过一个叫可复制集的机制提供。集群中的节点配置为自动同步数据,而且在服务器出错十自动容灾。MongDB还有一种旧的复制方法:主从复制。通常复制数据的时候,数据同步到了大部分(大于50%,好比说三台机器中的两台)节点就能够认为复制操做完成。可复制集应该保护至少3个成员,其中一个能够当裁判。
分片:分片是把大型数据集进行分区成更小的可管理的片的过程。简单来讲就是一台MongoDB服务器盛不下或处理不了那么多数据(1,2,3,4,5,6)了,就将这些数据分到三台小点的机子上,分别维护(1,4)(2,5)(3,6)
《MongoDB实战》