0
点赞
收藏
分享

微信扫一扫

mongodb 《六》高级命令


mongodb关系
数据类型
{
name:"ss"
address:[
{ss:"zz“},
{ss:"zz“}
]
}
嵌入式关系查询语法
db.users.findOne({"name":"ss"},{"address":1})

引用式关系查询语法
{
name:"ss"
address:[
ObjectId("42ffc4a5d85242602e001000"), ObjectId("31ffc4a5d85242602e002000")
]
}
>var result = db.users.findOne({"name":"ss"},{"address_ids":1})
>var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})


MongoDB 数据库引用

DBRef的形式:

{ $ref : , $id : , $db : }
三个字段表示的意义为:

$ref:集合名称
$id:引用的id
$db:数据库名称,可选参数

实例 address
{
"_id":ObjectId("11402597d852426020000002"),
"address": {
"$ref": "SET_NAME",
"$id": ObjectId("234009e4d852427820000002"),
"$db": "runoob"},
"name": "ss"
}

>var user = db.users.findOne({"name":"ss"})
>var dbRef = user.address
>db[dbRef.$ref].findOne({"_id":(dbRef.$id)})
#调用集合 调用查询 调用id

{
"_id" : ObjectId("234009e4d852427820000002"),
"building" : "csd",
"state" : "zs"
}


MongoDB 覆盖索引查询

数据
{
"_id": ObjectId("53402597d852426020000002"),
"contact": "9879654321",
"gender": "M",
"name": "lvbu",
"user_name": "diaochan"
}

创建联合索引,字段为 gender 和 user_name :
>db.users.ensureIndex({gender:1,user_name:1})

该索引会覆盖以下查询:
>db.users.find({gender:"M"},{user_name:1,_id:0})
MongoDB的不会去数据库文件中查找。相反,它会从索引中提取数据,这是非常快速的数据查询。


实例没有排除_id,查询就不会被覆盖:
>db.users.find({gender:"M"},{user_name:1})

这俩个不能使用覆盖索引查询:
所有索引字段是一个数组
所有索引字段是一个子文档


MongoDB 查询分析

explain()

创建 gender 和 user_name 的索引:

>db.users.ensureIndex({gender:1,user_name:1})
db.users.find({gender:"M"},{user_name:1,_id:0}).explain()

return

{
"cursor" : "BtreeCursor gender_1_user_name_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 0,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 0,
"nscannedAllPlans" : 1,
"scanAndOrder" : false,
"indexOnly" : true,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"gender" : [
[
"ss",
"ss"
]
],
"user_name" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
}

indexOnly: 字段为 true ,表示我们使用了索引。
cursor:因为这个查询使用了索引,MongoDB 中索引存储在B树结构中,所以这是也使用了 BtreeCursor 类型的游标。如果没有使用索引,游标的类型是 BasicCursor。这个键还会给出你所使用的索引的名称,你通过这个名称可以查看当前数据库下的system.indexes集合(系统自动创建,由于存储索引信息,这个稍微会提到)来得到索引的详细信息。
n:当前查询返回的文档数量。
nscanned/nscannedObjects:表明当前这次查询一共扫描了集合中多少个文档,我们的目的是,让这个数值和返回文档的数量越接近越好。
millis:当前查询所需时间,毫秒数。
indexBounds:当前查询具体使用的索引。


hint 强制 MongoDB 使用一个指定的索引

使用 gender 和 user_name 索引字段来查询:
>db.users.ensureIndex({gender:1,user_name:1})
>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})
可以使用 explain() 函数来分析以上查询:

>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1}).explain()







MongoDB 原子操作

判断当前是否可以执行原子操作
db.collection.findAndModify()

同一个文档中嵌入的 available 和 checkout 字段来确保这些字段是同步更新的:
db.books.findAndModify ( {
query: {
_id: 123451226789,
available: { $gt: 0 }
},
update: {
$inc: { available: -1 },
$push: { checkout: { by: "abc", date: new Date() } }
}
} )

原子操作常用命令
$set
用来指定一个键并更新键值,若键不存在并创建。

{ $set : { field : value } }
$unset
用来删除一个键。

{ $unset : { field : 1} }
$inc
$inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。

{ $inc : { field : value } }
$push
用法:

{ $push : { field : value } }
把value追加到field里面去,field一定要是数组类型才行,如果field不存在,会新增一个数组类型加进去。

$pushAll
同$push,只是一次可以追加多个值到一个数组字段内。

{ $pushAll : { field : value_array } }
$pull
从数组field内删除一个等于value值。

{ $pull : { field : _value } }
$addToSet
增加一个值到数组内,而且只有当这个值不在数组内才增加。

$pop
删除数组的第一个或最后一个元素

{ $pop : { field : 1 } }
$rename
修改字段名称

{ $rename : { old_field_name : new_field_name } }
$bit
位操作,integer类型

{$bit : { field : {and : 5}}}
偏移操作符
> t.find() { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 3 }, { "by" : "jane", "votes" : 7 } ] }

> t.update( {'comments.by':'joe'}, {$inc:{'comments.$.votes':1}}, false, true )



MongoDB 高级索引
{"tags": [
"music",
"cricket",
"blogs"
]}

创建数组索引:

>db.users.ensureIndex({"tags":1})
创建索引后,我们可以这样检索集合的 tags 字段:

>db.users.find({tags:"cricket"})
为了验证我们使用使用了索引,可以使用 explain 命令:

>db.users.find({tags:"cricket"}).explain()

{
"address": {
"city": "Los Angeles",
"state": "California",
"pincode": "123"
}
}

创建子文档索引

>db.users.ensureIndex({"address.city":1,"address.state":1,"address.pincode":1})
一旦创建索引,我们可以使用子文档的字段来检索数据:

>db.users.find({"address.city":"Los Angeles"})
查询表达不一定遵循指定的索引的顺序,mongodb 会自动优化。所以上面创建的索引将支持以下查询:

>db.users.find({"address.state":"California","address.city":"Los Angeles"})
同样支持以下查询:

>db.users.find({"address.city":"Los Angeles","address.state":"California","address.pincode":"123"})


MongoDB 索引限制
额外开销
每个索引占据一定的存储空间,在进行插入,更新和删除操作时也需要对索引进行操作。所以,如果你很少对集合进行读取操作,建议不使用索引。

内存(RAM)使用
由于索引是存储在内存(RAM)中,你应该确保该索引的大小不超过内存的限制。

如果索引的大小大于内存的限制,MongoDB会删除一些索引,这将导致性能下降。

查询限制
索引不能被以下的查询使用:

正则表达式及非操作符,如 $nin, $not, 等。
算术运算符,如 $mod, 等。
$where 子句
所以,检测你的语句是否使用索引是一个好的习惯,可以用explain来查看。

索引键限制
从2.6版本开始,如果现有的索引字段的值超过索引键的限制,MongoDB中不会创建索引。

插入文档超过索引键限制
如果文档的索引字段值超过了索引键的限制,MongoDB不会将任何文档转换成索引的集合。与mongorestore和mongoimport工具类似。

最大范围
集合中索引不能超过64个
索引名的长度不能超过128个字符
一个复合索引最多可以有31个字段


MongoDB Map Reduce

MapReduce的基本语法:
>db.collection.mapReduce(
function() {emit(key,value);}, //map 函数
function(key,values) {return reduceFunction}, //reduce 函数
{
out: collection,
query: document,
sort: document,
limit: number
}
)
Map 函数必须调用 emit(key, value) 返回键值对。

参数说明:
map :映射函数 (生成键值对序列,作为 reduce 函数参数)。
reduce 统计函数,reduce函数的任务就是将key-values变成key-value,也就是把values数组变成一个单一的值value。。
out 统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)。
query 一个筛选条件,只有满足条件的文档才会调用map函数。(query。limit,sort可以随意组合)
sort 和limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制
limit 发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)

{
"post_text": "szz",
"user_name": "runoob",
"status":"c"
}
{
"post_text": "szzsssd",
"user_name": "runoob",
"status":"active"
}
{
"post_text": "szzsssd",
"user_name": "runoobs",
"status":"active"
}
将在 posts 集合中使用 mapReduce 函数来选取已发布的文章(status:"active"),并通过user_name分组,计算每个用户的文章数:

>db.posts.mapReduce(
function() { emit(this.user_name,1); },
function(key, values) {return Array.sum(values)},
{
query:{status:"active"},
out:"post_total"
}
)
以上 mapReduce 输出结果为:

{
"result" : "post_total",
"timeMillis" : 23,
"counts" : {
"input" : 5,
"emit" : 5,
"reduce" : 1,
"output" : 2
},
"ok" : 1
}

result:储存结果的collection的名字,这是个临时集合,MapReduce的连接关闭后自动就被删除了。
timeMillis:执行花费的时间,毫秒为单位
input:满足条件被发送到map函数的文档个数
emit:在map函数中emit被调用的次数,也就是所有集合中的数据总量
ouput:结果集合中的文档个数(count对调试非常有帮助)
ok:是否成功,成功为1
err:如果失败,这里可以有失败原因,不过从经验上来看,原因比较模糊,作用不大




创建全文索引
>db.posts.ensureIndex({post_text:"text"})

使用全文索引
>db.posts.find({$text:{$search:"runoob"}})

旧版本的 MongoDB,你可以使用以下命令:
>db.posts.runCommand("text",{search:"runoob"})

删除全文索引
db.posts.getIndexes() #查询
db.posts.dropIndex("post_text_text") #删除




MongoDB 正则表达式


正则表达式查找包含 runoob 字符串的文章:

>db.posts.find({post_text:{$regex:"runoob"}})
以上查询也可以写为:

>db.posts.find({post_text:/runoob/})

设置 $options 为 $i。

以下命令将查找不区分大小写的字符串 runoob:

>db.posts.find({post_text:{$regex:"runoob",$options:"$i"}})

在数组字段中使用正则表达式来查找内容
以 run 开头的标签数据(ru 或 run 或 runoob)
db.posts.find({tags:{$regex:"run"}})

优化正则表达式查询
如果你的文档中字段设置了索引,那么使用索引相比于正则表达式匹配查找所有的数据查询速度更快。
如果正则表达式是前缀表达式,所有匹配的数据将以指定的前缀字符串为开始。例如: 如果正则表达式为 ^tut ,查询语句将查找以 tut 为开头的字符串。
这里面使用正则表达式有两点需要注意:

正则表达式中使用变量。一定要使用eval将组合的字符串进行转换,不能直接将字符串拼接后传入给表达式。否则没有报错信息,只是结果为空!实例如下:

var name=eval("/" + 变量值key +"/i");
以下是模糊查询包含title关键词, 且不区分大小写:

title:eval("/"+title+"/i") // 等同于 title:{$regex:title,$Option:"$i"}

MongoDB 管理工具: Rockmongo
RockMongo是PHP5写的一个MongoDB管理工具。

通过 Rockmongo 你可以管理 MongoDB服务,数据库,集合,文档,索引等等。


MongoDB GridFS
GridFS 用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频、视频等)。

GridFS 也是文件存储的一种方式,但是它是存储在MonoDB的集合中。

GridFS 可以更好的存储大于16M的文件。

GridFS 会将大文件对象分割成多个小的chunk(文件片段),一般为256k/个,每个chunk将作为MongoDB的一个文档(document)被存储在chunks集合中。

GridFS 用两个集合来存储一个文件:fs.files与fs.chunks。

每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中

以下是简单的 fs.files 集合文档:

{
"filename": "test.txt",
"chunkSize": NumberInt(261120),
"uploadDate": ISODate("2014-04-13T11:32:33.557Z"),
"md5": "7b762939321e146569b07f72c62cca4f",
"length": NumberInt(646)
}
以下是简单的 fs.chunks 集合文档:

{
"files_id": ObjectId("534a75d19f54bfec8a2fe44b"),
"n": NumberInt(0),
"data": "Mongo Binary Data"
}


GridFS 添加文件

mongofiles.exe -d gridfs put f:w1.png
show dbs
use gridfs
>db.fs.files.find()

{
_id: ObjectId('534a811bf8b4aa4d33fdf94d'),
filename: "song.mp3",
chunkSize: 261120,
uploadDate: new Date(1397391643474), md5: "e4f53379c909f7bed2e9d631e15c1c41",
length: 10401959
}

db.fs.chunks.find({files_id:ObjectId('534a811bf8b4aa4d33fdf94d')})



MongoDB 固定集合(Capped Collections)

通过createCollection来创建一个固定集合 指定文档个数,加上max:1000属性
>db.createCollection("cappedLogCollection",{capped:true,size:10000,max:1000})

判断集合是否为固定集合
>db.cappedLogCollection.isCapped()

将已存在的集合转换为固定集合可以使用以下命令 已存在的 posts 集合转换为固定集合
>db.runCommand({"convertToCapped":"posts",size:10000})

固定集合查询
固定集合文档按照插入顺序储存的,默认情况下查询就是按照插入顺序返回的,也可以使用$natural调整返回顺序。

>db.cappedLogCollection.find().sort({$natural:-1})

固定集合的功能特点
可以插入及更新,但更新不能超出collection的大小,否则更新失败,不允许删除,但是可以调用drop()删除集合中的所有行,但是drop后需要显式地重建集合。

在32位机子上一个cappped collection的最大值约为482.5M,64位上只受系统文件大小的限制。

固定集合属性及用法
属性
属性1:对固定集合进行插入速度极快
属性2:按照插入顺序的查询输出速度极快
属性3:能够在插入最新数据时,淘汰最早的数据
用法
用法1:储存日志信息
用法2:缓存一些少量的文档

db.createCollection("cappedLogCollection",{capped:true,size:10000,max:1000})
size 是整个集合空间大小,单位为【KB】

max 是集合文档个数上线,单位是【个】

如果空间大小到达上限,则插入下一个文档时,会覆盖第一个文档;如果文档个数到达上限,同样插入下一个文档时,会覆盖第一个文档。两个参数上限判断取的是【与】的逻辑。


MongoDB自动增长

设置一个数据集
db.ids.save({name:"user", id:0});
调用一次加加
>var userid = db.ids.findAndModify({update:{$inc:{'id':1}}, query:{"name":"user"}, new:true});

使用uuid
>db.user.save({uid:userid.id, username:"dotcoo", password:"dotcoo", info:"ssssssss"});














 

举报

相关推荐

0 条评论