14、mongodb 监控
mongostat 命令
它会间隔固定时间 获取mongodb的当前运行状态,并输出
启动你的Mongod服务,进入到你安装的MongoDB目录下的bin目录, 然后输入mongostat
命令,如下所示:
D:\set up\mongodb\bin>mongostat
mongotop命令
用来跟踪一个MongoDB的实例,查看哪些大量的时间花费在 读取和写入数据。
mongotop提供每个集合的水平的统计数据。默认情况下,mongotop返回值的每一秒。
如下所示:
D:\set up\mongodb\bin>mongotop
15、mongodb 查询分析
使用 explain()
explain 操作提供了查询信息,使用索引及查询统计等。有利于我们对索引的优化。
接下来我们在 users 集合中创建 gender 和 user_name 的索引:
db.users.ensureIndex({gender:1,user_name:1})
db.users.find({gender:"M"},{user_name:1,_id:0}).explain()
查看返回结果集的字段:
indexOnly: 字段为 true ,表示我们使用了索引。
cursor:因为这个查询使用了索引,MongoDB中索引存储在B树结构中,所以这是也使用了
BtreeCursor类型的游标。如果没有使用索引,游标的类型是BasicCursor。这个键
还会给出你所使用的索引的名称,你通过这个名称可以查看当前数据库下的
system.indexes集合(系统自动创建,由于存储索引信息,这个稍微会提到)来得到
索引的详细信息。
n:当前查询返回的文档数量。
nscanned/nscannedObjects:表明当前这次查询一共扫描了集合中多少个文档,我们的目的是让这个数值和返回文档的数量越接近越好。
millis:当前查询所需时间,毫秒数。
indexBounds:当前查询具体使用的索引。
使用 hint()
虽然MongoDB查询优化器一般工作的很不错,但是也可以使用hints来强迫MongoDB使用
一个指定的索引。
这种方法某些情形下会提升性能。 一个有索引的collection并且执行一个多字段的查询
(一些字段已经索引了)。
如下查询实例指定了使用 gender 和 user_name 索引字段来查询:
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()
16、mongodb 原子操作
所谓原子操作就是要么这个文档保存到Mongodb,要么没有保存到Mongodb,不会出现查
询到的文档没有保存完整的情况。
比如文档的保存,修改,删除等,都是原子操作。
$set
用来指定一个键并更新键值,若键不存在并创建。
{ $set : { field : value } }
$unset
用来删除一个键。
{ $unset : { field : 1} }
$inc
$inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。
{ $inc : { field : value } }
$push用法:
{ $push : { field : value } }
$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 )
> t.find() { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" :
[ { "by" : "joe", "votes" : 4 }, { "by" : "jane", "votes" : 7 } ] }
17、mongodb ObjecctId
ObjectId 是一个12字节 BSON 类型数据,有以下格式:
(1)前4个字节表示时间戳
(2)接下来的3个字节是机器标识码
(3)紧接的两个字节由进程id组成(PID)
(4)最后三个字节是随机数。
创建新的ObjectId
使用以下代码生成新的ObjectId:
newObjectId = ObjectId()
上面的语句返回以下唯一生成的id:
ObjectId("5349b4ddd2781d08c09890f3")
创建文档的时间戳
由于 ObjectId 中存储了 4 个字节的时间戳,所以你不需要为你的文档保存时间戳字段,
你可以通过 getTimestamp 函数来获取文档的创建时间:
ObjectId("5349b4ddd2781d08c09890f4").getTimestamp()
ObjectId 转换为字符串
在某些情况下,您可能需要将ObjectId转换为字符串格式。你可以使用下面的代码:
new ObjectId().str
以上代码将返回Guid格式的字符串: 5349b4ddd2781d08c09890f3
18、MongoDB Map Reduce
Map-Reduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,
然后再将结果合并成最终结果(REDUCE)。
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 :映射函数 (生成键值对序列,作为 reduce 函数参数)。
reduce 统计函数,reduce函数的任务就是将key-values变成key-value,也就是把values数组
变成一个单一的值value。。
out 统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)。
query 一个筛选条件,只有满足条件的文档才会调用map函数。
(query。limit,sort可以随意组合)
sort 和limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制
limit 发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)
计算每个用户的文章数:
>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
}
结果表明,共有4个符合查询条件(status:"active")的文档, 在map函数中生成了4个键值对
文档,最后使用reduce函数将相同的键值分为两组。
具体参数说明:
result:储存结果的collection的名字,这是个临时集合,MapReduce的连接关闭后自动就被删除了。
timeMillis:执行花费的时间,毫秒为单位
input:满足条件被发送到map函数的文档个数
emit:在map函数中emit被调用的次数,也就是所有集合中的数据总量
ouput:结果集合中的文档个数(count对调试非常有帮助)
ok:是否成功,成功为1
err:如果失败,这里可以有失败原因,不过从经验上来看,原因比较模糊,作用不大
19、mongodb 正则表达式
MongoDB 使用 $regex 操作符来设置匹配字符串的正则表达式。
以下命令使用正则表达式查找包含 w3cschool.cc 字符串的文章:
db.posts.find({post_text:{$regex:"w3cschool.cc"}})
以上查询也可以写为:
>db.posts.find({post_text:/w3cschool.cc/})
不区分大小写的正则表达式 ,我们可以设置 $options 为 $i。
db.posts.find({post_text:{$regex:"w3cschool.cc",$options:"$i"}})
{
"_id" : ObjectId("53493d37d852429c10000004"),
"post_text" : "hey! this is my post on W3Cschool.cc",
"tags" : [ "tutorialspoint" ]
}
数组元素使用正则表达式
如果你需要查找包含以 tutorial 开头的标签数据(tutorial 或 tutorials 或 tutorialpoint 或
tutorialphp), 你可以使用以下代码:
>db.posts.find({tags:{$regex:"tutorial"}})
优化正则表达式查询
如果你的文档中字段设置了索引,那么使用索引相比于正则表达式匹配查找所有的数据查
询速度更快。
如果正则表达式是前缀表达式,所有匹配的数据将以指定的前缀字符串为开始。
例如: 如果正则表达式为 ^tut ,查询语句将查找以 tut 为开头的字符串。
这里面使用正则表达式有两点需要注意:
正则表达式中使用变量。一定要使用eval将组合的字符串进行转换,不能直接将字符串拼接
后传入给表达式。否则没有报错信息,只是结果为空!实例如下:
var name=eval("/" + 变量值key +"/i");
以下是模糊查询包含title关键词, 且不区分大小写:
title:eval("/"+title+"/i") // 等同于 title:{$regex:title,$Option:"$i"}
20、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 添加文件
现在我们使用 GridFS 的 put 命令来存储 mp3 文件。 调用 MongoDB 安装目录下bin的 mongofiles.exe工具。
打开命令提示符,进入到MongoDB的安装目录的bin目录中,找到mongofiles.exe,并输入下面的代码:
>mongofiles.exe -d gridfs put song.mp3
GridFS 是存储文件的数据名称。如果不存在该数据库,MongoDB会自动创建。Song.mp3 是音频文件名。
使用以下命令来查看数据库中文件的文档:
>db.fs.files.find()
以上命令执行后返回以下文档数据:
{
_id: ObjectId('534a811bf8b4aa4d33fdf94d'),
filename: "song.mp3",
chunkSize: 261120,
uploadDate: new Date(1397391643474), md5: "e4f53379c909f7bed2e9d631e15c1c41",
length: 10401959
}
我们可以看到 fs.chunks 集合中所有的区块,以下我们得到了文件的 _id 值,我们可以根据这个 _id 获取区块(chunk)的数据:
>db.fs.chunks.find({files_id:ObjectId('534a811bf8b4aa4d33fdf94d')})
以上实例中,查询返回了 40 个文档的数据,意味着mp3文件被存储在40个区块中。