mirror of
https://github.com/tiennm99/zfoo.git
synced 2026-05-20 05:27:48 +00:00
689 lines
26 KiB
Markdown
689 lines
26 KiB
Markdown
# 一、MongoDB常用命令
|
||
|
||
## 1.数据库常用命令
|
||
|
||
```
|
||
show dbs # 查询数据库列表
|
||
use student # 该命令如果数据库不存在,将创建一个新的数据库,否则将返回现有的数据库。
|
||
db.dropDatabase() # 删除新的数据库
|
||
db.repairDatabase() # 整理数据库,不仅能整理碎片还可以回收磁盘空间,但是会产生锁,建议停服的时候做
|
||
db.getName() # 查看当前使用的数据库
|
||
db.version() # 当前db的版本
|
||
db.getMongo() # 查看当前db的链接机器地址
|
||
db.getPrevError() # 查询之前的错误信息
|
||
db.resetError() # 清除错误记录
|
||
db.help() # 查看数据库帮助文档
|
||
```
|
||
|
||
## 2.集合常用命令
|
||
|
||
```
|
||
show collections # 查看所有的集合
|
||
db.createCollection("student") # 创建一个集合
|
||
db.createCollection("log", {size: 20, capped:true, max: 100}); # 或者带参数创建固定集合
|
||
db.student # 使用集合
|
||
db.student.drop() # 删除当前集合
|
||
db.student.validate() # 验证集合是否有问题,验证集合内容
|
||
|
||
|
||
db.student.count() # 查询当前集合的数据条数
|
||
db.student.dataSize() # 查看集合数据大小
|
||
db.student.totalIndexSize() # 查看集合索引大小
|
||
db.student.storageSize() # 集合分配的空间大小,包括未使用的空间
|
||
db.student.totalSize() # 显示集合总大小,包括索引和数据的大小和分配空间的大小
|
||
db.student.getDB() # 显示当前集合所在的db
|
||
db.student.stats() # 显示当前集合的状态
|
||
db.student.getShardVersion() # 集合的分片版本信息
|
||
db.student.renameCollection("students"); # 集合重命名
|
||
db.printCollectionStats() # 显示当前db所有集合的状态信息
|
||
db.student.help() # 查看集合命令帮助文档
|
||
```
|
||
|
||
- 集合内存
|
||
|
||
```
|
||
在MongoDB中并不需要创建集合。 当插入一些文档 MongoDB 会自动创建集合。
|
||
capped: Boolean
|
||
(可选)如果为true,它启用上限集合。上限集合是一个固定大小的集合,当它达到其最大尺寸会自动覆盖最老的条目。
|
||
如果指定true,则还需要指定参数的大小
|
||
size: number (可选)指定的上限集合字节的最大尺寸。如果capped 是true,那么还需要指定这个字段
|
||
autoIndexID Boolean (可选)如果为true,自动创建索引_id字段。默认的值是 false
|
||
max number (可选)指定上限集合允许的最大文件数
|
||
|
||
DB.createCollection("student", { capped : true, size : 6142800, autoIndexId : true, max : 10000 })
|
||
DB.createCollection("student")
|
||
```
|
||
|
||
## 3. 文档常用命令
|
||
|
||
### 增
|
||
|
||
```
|
||
db.student.insert({name:"jay", age: 100})
|
||
|
||
如果我们不指定_id参数插入的文档,那么 MongoDB 将为文档分配一个唯一的ObjectId。_id 是12个字节十六进制数在一个集合的每个文档是唯一的。
|
||
0-3时间戳,4-6机器唯一标识的散列标识,7-8进程号PID,9-11计数器。前三个保证同一个机器不同进程产生的标识唯一,后一个保证同一个进程产生不同的标识。
|
||
简介说就是在分布式系统中可以在本机产生全局唯一id。
|
||
```
|
||
|
||
### 删
|
||
|
||
```
|
||
db.student.remove({name : "jay"},true); # true是只删除一条,默认是false全部删除
|
||
db.student.remove({name : "jay"});
|
||
```
|
||
|
||
### 改
|
||
|
||
```
|
||
db.student.save({name : "jay", age : 20}) # save如果数据库已经有这条数据,则会更新它;如果没有,则写入
|
||
|
||
db.student.update({name:"jay"},{$set:{age : 20, company: "google"}});
|
||
db.student.update({name:"jay"},{$set:{age : 20}},{multi:true}); # $set修改器;multi默认false,只更新找到的第一条记录
|
||
db.student.update({name:"jay"},{$unset:{company:1}}); # $unset用于取消字段,去掉文档中的某个字段
|
||
db.student.update({name:"jay"},{$inc: {age: 50}}); # $inc用于增加或减少数值
|
||
db.student.update({name:"jay"},{$push: {phone: {home:456789}}}); # $push用于把元素追加到数组中,如果字段不存在,会新增
|
||
db.student.update({name:"jay"},{$pushAll: {phone: [{home:456789} # $pushAll用于把元素追加到数组中,多个元素
|
||
db.student.update({name:"jay"},{$pull: {phone:{home: 456789} }}); # $pull删除数组中满足条件的元素
|
||
db.student.update({name:"jay"},{$addToSet: {phone: {home:456789}}}); # $addToSet类似于push,但是只有这个值不在数组中才会增加
|
||
db.student.update({name:"jay"},{$pop: {phone:1}}); # $pop删除数组中最后一个元素
|
||
db.student.update({name:"jay"},{$rename: {phone:"call"}}); # $rename修改字段名称
|
||
```
|
||
|
||
### 查
|
||
|
||
```
|
||
db.student.find()
|
||
db.student.find().pretty(); # 如果需要结构化显示返回的文档可以加上pretty()方法
|
||
db.student.find({name:"jay"},{age:1}) # 查询name伟jay,只显示age
|
||
|
||
db.student.count({$or: [{age: 14}, {age: 28}]}); # 查询满足条件的文档数量
|
||
```
|
||
|
||
## 4.索引
|
||
|
||
### 创建索引
|
||
|
||
```
|
||
db.student.ensureIndex({age: 1}); # 1表示age索引按升序排序
|
||
db.student.ensureIndex({name: 1, age: -1}); # -1表示同组文档按降序排序
|
||
|
||
例如我们有数据:
|
||
{"name":"jay",age:14}
|
||
{"name":"ad",age:14}
|
||
{"name":"ad",age:38}
|
||
{"name":"ad",age:24}
|
||
{"name":"ab",age:14}
|
||
使用db.student.ensureIndex({name: 1, age: -1})建议索引后,索引中的数据组织为:
|
||
{"name":"ab",age:14}
|
||
{"name":"ad",age:38}
|
||
{"name":"ad",age:24}
|
||
{"name":"ad",age:14}
|
||
{"name":"jay",age:14}
|
||
```
|
||
|
||
### 创建唯一索引
|
||
|
||
```
|
||
db.student.ensureIndex({name:1},{unique:true}) # 如果创建唯一索引时已经存在重复项,通过dropDups在创建唯一索引时消除重复文档
|
||
db.student.ensureIndex({name:1},{unique:true,dropDups:true})
|
||
```
|
||
|
||
### 索引操作
|
||
|
||
```
|
||
db.student.getIndexes(); # 查询集合所有索引
|
||
db.student.totalIndexSize(); # 查看集合总索引记录大小
|
||
db.student.reIndex(); # 修复索引
|
||
db.student.dropIndex("name");# 删除指定索引
|
||
```
|
||
|
||
### 索引调优explain
|
||
|
||
```
|
||
db.student.find({name: "jaysunxiao" }).explain();
|
||
```
|
||
|
||
## 5.查询
|
||
|
||
### 单个文档大小
|
||
|
||
```
|
||
Object.bsonsize(db.user.findOne({'account':'xxx'})) # 返回文档的bytes数量
|
||
```
|
||
|
||
### 迭代器,一般用于遍历数据集。通过hasNext()判断是否有下一条数据,next()获取下一条数据
|
||
|
||
```javascript
|
||
var iterator= db.student.find();
|
||
while(iterator.hasNext()){
|
||
let temp=iterator.next();
|
||
print(temp.name);
|
||
}
|
||
|
||
// 迭代器还实现了迭代器接口,所以可以使用forEach。
|
||
var iterator= db.student.find();
|
||
iterator.forEach(function(temp){
|
||
print(temp.name);
|
||
});
|
||
```
|
||
|
||
### find语法
|
||
|
||
```
|
||
find( query, fields)
|
||
query 查询条件,相当于sql的where
|
||
fields 查询的结果,字段映射,0不显示,1显示
|
||
explain("allPlansExecution") 返回查询计划信息和查询计划的执行统计信息
|
||
|
||
db.student.find({}, { "_id":0, "name":1}).limit(9).skip(5).sort({"name":-1}).pretty()
|
||
```
|
||
|
||
### 条件查询
|
||
|
||
```
|
||
db.student.find({name:"jay",age:16}) # 与操作
|
||
db.student.find({$or: [{age: 14}, {age: 28}]}); # 或操作$or
|
||
db.student.find({age: {$gt: 20}}) # 大于$gt
|
||
db.student.find({age: {$lt: 20}}) # 小于$lt
|
||
db.student.find({age: {$gte: 20}}) # 大于等于$gte
|
||
db.student.find({age: {$lte: 20}}) # 小于等于$lte
|
||
db.student.find({name: { $type : "string" }}); # 类型查询$type
|
||
|
||
db.student.find({age: {$exists: true}}) # 是否存在$exists
|
||
db.student.find({age: {$mod : [10, 0]}}); # 取模$mod
|
||
db.student.find({age: { "$ne" : 23}}) # 不等于$ne
|
||
db.student.find({name:{ "$in" : [ "jay" , "ab"]}}) # 包含$in
|
||
db.student.find({name:{$not:{"$in":["jay","ab"]}}})# 取非
|
||
db.student.find({name:{ "$nin":["jay","ab"]}}) # 不包含$nin
|
||
```
|
||
|
||
### null查询
|
||
|
||
```
|
||
db.student.find({company:null}) # 查询company字段为null的文档
|
||
db.student.find({company:{$nin:[null]} }) # 查询company字段不为空的文档\
|
||
```
|
||
|
||
### 正则查询
|
||
|
||
```
|
||
db.student.find({"name":/^j/}) # 以j开头的字符串
|
||
```
|
||
|
||
### 嵌套查询
|
||
|
||
```
|
||
db.student.find({"phone":{"home" : 123321,"mobile" : 15820123123}}) # 指定完整的文档,查询出子文档完全匹配指定文档的文档。
|
||
db.student.find({"phone.home":123321}) # 如果我们不知道子文档的完整文档,只知道子文档中一个字段的值,可以通过点查询。
|
||
```
|
||
|
||
### 数组查询
|
||
|
||
```
|
||
db.student.find({favorite_number :[6, 8]}); # 精确匹配查询
|
||
db.student.find({favorite_number:6}); # 数组单元素查询
|
||
db.student.find({favorite_number : {$all : [6, 8]}}); # 数组多元素查询
|
||
db.student.find({favorite_number: {$size: 3}}); # $size数组长度查询
|
||
db.student.find({},{favorite_number: {$slice: 2}}); # $slice返回数组子集
|
||
db.student.find({},{favorite_number: {$slice: -2}});
|
||
db.student.find({phone.home:123456}); # 点查询用于查询更复杂的数组,例如数组中包含的是子文档的情况
|
||
db.student.find({phone.home:123456,"phone.mobile":13820123123}); # 数组的子文档如果有多个字段,查询出子文档同时满足两个条件的文档有两种方式
|
||
db.student.find( { # 或者,两者等价
|
||
phone: {
|
||
$elemMatch: {
|
||
home :123456,
|
||
mobile: 13820123123
|
||
}}})
|
||
```
|
||
|
||
### 索引查询
|
||
|
||
```
|
||
db.student.find({favorite_number.0:6}); # 数组都有索引,例如[6,8],6是第0个元素,8是第1个元素(数组索引以0开头)。要查找某个元素指定值的文档可以使用点和索引值
|
||
db.student.find({phone.2.home:123456}); # 点查询中只要数组的子文档里有一个home值满足查询值就会返回文档。如果我们要精确到第几个元素也可以用索引查询。
|
||
```
|
||
|
||
### 高级查询$where
|
||
|
||
- Javascript与$where结合使用,下面的全部等价
|
||
|
||
```
|
||
db.student.find({age: {$gt: 18}});
|
||
db.student.find({$where: "this.age > 18"});
|
||
db.student.find("this.age > 18");
|
||
f = function() {return this.age > 18}; db.student.find(f);
|
||
```
|
||
|
||
## 6.聚合查询
|
||
|
||
### count和distinct
|
||
|
||
```
|
||
db.student.count({age: {$gte: 18}}) # 数量查询count
|
||
db.runCommand({"distinct":"student", "key":"age"}) # 不同值distinct
|
||
```
|
||
|
||
### 分组group
|
||
|
||
```
|
||
db.collection.group({
|
||
key:{field:1},
|
||
initial:{count:0},
|
||
cond:{},
|
||
reduce: function ( curr, result ) { },
|
||
keyf:function(doc){},
|
||
finalize:function(result) {}
|
||
})
|
||
|
||
|
||
数据如下:
|
||
{ "_id" : ObjectId("58d9b6afa159504ca6c572e0"), "name" : "jay", "age" : 28, "company" : "google", "name" : "a2" }
|
||
{ "_id" : ObjectId("58d9ba2d6097167df6313438"), "name" : "jay", "age" : 14 }
|
||
{ "_id" : ObjectId("58d9ba2d6097167df6313439"), "name" : "ad", "age" : 14 }
|
||
{ "_id" : ObjectId("58d9ba2d6097167df631343a"), "name" : "ad", "age" : 38 }
|
||
{ "_id" : ObjectId("58d9ba2d6097167df631343b"), "name" : "ad", "age" : 24 }
|
||
{ "_id" : ObjectId("58d9ba2e6097167df631343c"), "name" : "ab", "age" : 14 }
|
||
|
||
|
||
我们这里可以做一个统计:每个年龄有多少人,则使用age字段作为key,在reduce时进行同组的数量计数,finalize中组织结果文档格式。
|
||
使用代码如下:
|
||
db.student.group({
|
||
key:{age:1},
|
||
initial:{count:0},
|
||
cond:{"age":{$gt:13}},
|
||
reduce: function(curr,result) {
|
||
result.count += 1;
|
||
},
|
||
finalize:function(result) {
|
||
result.年龄=result.age;
|
||
result.人数=result.count;
|
||
}
|
||
});
|
||
|
||
|
||
使用MapReduce做一个统计:每个年龄有多少人,this表示当前文档,使用this.age的值作为key。在reduce时进行同组的数量计数,finalize中组织结果文档格式。
|
||
代码如下:
|
||
db.student.mapReduce(
|
||
function () {
|
||
emit(this.age, {age: this.age, count: 1});
|
||
},
|
||
function (key, values) {
|
||
var count = 0;
|
||
values.forEach(function(val) {
|
||
count += val.count;
|
||
});
|
||
return {age: key, count: count};
|
||
},
|
||
{
|
||
out: { inline : 1 },
|
||
finalize: function (key, reduced) {
|
||
return {"年龄": reduced.age, "人数": reduced.count};
|
||
}
|
||
}
|
||
)
|
||
第一个function是map函数,提交两个参数key和value,数据会根据key的值进行分组,把同组的value的值放入values数组中。
|
||
第二个function是reduce函数,key和values是第一个map函数的分组结果。
|
||
第三个out指定结果集生成在什么地方,inline:1,表示结果集放在内存中,仅适用于结果集符合16MB限制的情况
|
||
```
|
||
|
||
### $project
|
||
|
||
```
|
||
数据如下:
|
||
{ "_id" : ObjectId("58d9ba2d6097167df6313438"), "name" : { "first" : "adrian", "last" : "jay" }, "age" : 14, "phone" : 111128912345 }
|
||
使用代码:
|
||
db.student.aggregate(
|
||
[
|
||
{ $project: { _id:0, age: 1, phone: "123456789", lastName: "$name.last" } }
|
||
]
|
||
)
|
||
$project映射结果集的文档结构,0表示排除字段,1显示字段,"123456789"直接赋值
|
||
```
|
||
|
||
### $match
|
||
|
||
```
|
||
db.student.aggregate([{$match:{"name.last":"jay"}}])
|
||
```
|
||
|
||
### $limit
|
||
|
||
```
|
||
db.student.aggregate({ $limit : 1 });
|
||
```
|
||
|
||
### $skip
|
||
|
||
```
|
||
db.student.aggregate({ $skip : 2 });
|
||
```
|
||
|
||
### $unwind
|
||
|
||
```
|
||
数据:
|
||
db.product.find()
|
||
{ "_id" : 1, "item" : "ABC1", "sizes" : [ "S", "M", "L" ] }
|
||
|
||
db.product.aggregate( [ { $unwind : "$sizes" } ] )
|
||
```
|
||
|
||
### $group
|
||
|
||
```
|
||
数据:
|
||
db.student.find()
|
||
{ "_id" : ObjectId("58d9ba2d6097167df6313438"), "name" : "jay", "age" : 14 }
|
||
{ "_id" : ObjectId("58d9ba2d6097167df6313439"), "name" : "ad", "age" : 14 }
|
||
{ "_id" : ObjectId("58d9ba2d6097167df631343a"), "name" : "ad", "age" : 38 }
|
||
|
||
把数据根据age字段进行分组,使用命令:
|
||
db.student.aggregate([{$group : {_id : "$age"}}])
|
||
```
|
||
|
||
### $sort
|
||
|
||
```
|
||
$sort将输入文档排序后输出,1为按字段升序,-1为降序。
|
||
我们有数据:
|
||
db.student.find()
|
||
{ "_id" : ObjectId("58d9ba2d6097167df6313438"), "name" : "jay", "age" : 14 }
|
||
{ "_id" : ObjectId("58d9ba2d6097167df6313439"), "name" : "ad", "age" : 14 }
|
||
{ "_id" : ObjectId("58d9ba2d6097167df631343a"), "name" : "ad", "age" : 38 }
|
||
使用命令:
|
||
db.student.aggregate([{$sort : {age :-1}}])
|
||
```
|
||
|
||
### $lookup
|
||
|
||
```
|
||
数据:
|
||
db.product.insert({"_id":1,"name":"产品1","price":99})
|
||
db.product.insert({"_id":2,"name":"产品2","price":88})
|
||
|
||
db.order.insert({"_id":1,"pid":1,"name":"订单1"})
|
||
db.order.insert({"_id":2,"pid":2,"name":"订单2"})
|
||
db.order.insert({"_id":3,"pid":2,"name":"订单3"})
|
||
db.order.insert({"_id":4,"pid":1,"name":"订单4"})
|
||
db.order.insert({"_id":5,"name":"订单5"})
|
||
db.order.insert({"_id":6,"name":"订单6"})
|
||
|
||
$lookup作左连接组合两个集合的信息使用命令如下:
|
||
db.order.aggregate([
|
||
{
|
||
$lookup:
|
||
{
|
||
from: "product",
|
||
localField: "pid",
|
||
foreignField: "_id",
|
||
as: "orderDetail"
|
||
}
|
||
}
|
||
])
|
||
|
||
```
|
||
|
||
### $geoNear
|
||
|
||
```
|
||
一、平面
|
||
|
||
我们使用lng和lat的命名,新建数据如下:
|
||
db.places.save({name:"肯德基",loc : { lng: 40.739037, lat: 73.992964 },category:"餐饮"})
|
||
db.places.save({name:"麦当劳",loc : { lng : 42.739037, lat: 73.992964 },category:"餐饮"})
|
||
db.places.save({name:"农行",loc : { lng: 41.739037, lat: 73.992964 },category:"银行"})
|
||
db.places.save({name:"地铁站",loc : { lng: 40.639037, lat: 73.992964 },category:"交通"})
|
||
|
||
2d索引创建方式如下:
|
||
db.places.createIndex( { "loc": "2d" } )
|
||
|
||
|
||
我们现在需要查到地铁站附近的文档信息,可以使用:
|
||
db.places.find({loc : {$near : { lng: 40.639037, lat:73.992964 }}})
|
||
|
||
|
||
|
||
aggregate和$geoNear能指定到范围,比如我们要查范围在坐标值相差2度(平面单位)以内的文档:
|
||
db.places.aggregate([
|
||
{
|
||
$geoNear: {
|
||
spherical:false,
|
||
distanceMultiplier:1,
|
||
near: { lng: 40.639037, lat:73.992964 },
|
||
distanceField: "dist.distacnce",
|
||
maxDistance: 2,
|
||
query: { category: "餐饮" },
|
||
includeLocs: "dist.location",
|
||
num: 1
|
||
}
|
||
}
|
||
])
|
||
|
||
二、球面
|
||
新建数据如下:
|
||
db.places.save({name:"肯德基",loc : { type: "Point", coordinates: [ 40.639037, 73.992964 ] },category:"餐饮"})
|
||
db.places.save({name:"麦当劳",loc : { type: "Point", coordinates: [ 42.739037, 73.992964 ] },category:"餐饮"})
|
||
db.places.save({name:"农行",loc : { type: "Point", coordinates: [ 41.739037, 73.992964 ] },category:"银行"})
|
||
db.places.save({name:"地铁站",loc : { type: "Point", coordinates: [ 40.639037, 73.992964 ] },category:"交通"})
|
||
|
||
创建2dsphere 索引使用代码:
|
||
db.places.createIndex( { loc : "2dsphere" } )
|
||
|
||
$geoNear用于输出某一地理位置2公里内的文档代码如下:
|
||
db.places.aggregate([
|
||
{
|
||
$geoNear: {
|
||
spherical: true,
|
||
near: { type: "Point", coordinates: [ 40.639037, 73.992964 ] },
|
||
distanceField: "dist.distacnce",
|
||
maxDistance: 2000,
|
||
query: { category:"餐饮" },
|
||
includeLocs: "dist.location",
|
||
num: 5
|
||
}
|
||
}
|
||
])
|
||
```
|
||
|
||
### $group和管道表达式
|
||
|
||
```
|
||
测试数据准备:
|
||
db.product.insert({"_id":1,"name":"产品1","price":99,"type":"服装"})
|
||
db.product.insert({"_id":2,"name":"产品2","price":88,"type":"服装"})
|
||
db.product.insert({"_id":3,"name":"产品3","price":29,"type":"饰品"})
|
||
db.product.insert({"_id":4,"name":"产品4","price":78,"type":"服装"})
|
||
db.product.insert({"_id":5,"name":"产品5","price":9,"type":"饰品"})
|
||
db.product.insert({"_id":6,"name":"产品6","price":18,"type":"饰品"})
|
||
|
||
|
||
db.product.aggregate([{$group : {_id : "$type", price : {$sum : "$price"}}}]) # 求和$sum
|
||
db.product.aggregate([{$group : {_id : "$type", price : {$avg : "$price"}}}]) # 平均值$avg
|
||
db.product.aggregate([{$group : {_id : "$type", price : {$min : "$price"}}}]) # 最小值$min
|
||
db.product.aggregate([{$group : {_id : "$type", price : {$max : "$price"}}}]) # 最大值$max
|
||
db.product.aggregate([{$group : {_id : "$type", tags : {$push : "$name"}}}]) # 数组添加$push
|
||
db.product.aggregate([{$group : {_id : "$type", tags : {$addToSet : "$name"}}}])# 数组添加$addToSet
|
||
db.product.aggregate([{$group : {_id : "$type", product : {$first : "$name"}}}])# 首元素$first
|
||
db.product.aggregate([{$group : {_id : "$type", product : {$last : "$name"}}}]) # 尾元素$last
|
||
```
|
||
|
||
### 复合使用示例
|
||
|
||
```
|
||
数据如下:
|
||
{ "_id" : ObjectId("58d9b6afa159504ca6c572e0"), "name" : "jay", "age" : 28, "company" : "google", "name" : "a2" }
|
||
{ "_id" : ObjectId("58d9ba2d6097167df6313438"), "name" : "jay", "age" : 14 }
|
||
{ "_id" : ObjectId("58d9ba2d6097167df6313439"), "name" : "ad", "age" : 14 }
|
||
{ "_id" : ObjectId("58d9ba2d6097167df631343a"), "name" : "ad", "age" : 38 }
|
||
{ "_id" : ObjectId("58d9ba2d6097167df631343b"), "name" : "ad", "age" : 24 }
|
||
{ "_id" : ObjectId("58d9ba2e6097167df631343c"), "name" : "ab", "age" : 14 }
|
||
|
||
使用代码如下:
|
||
db.student.aggregate(
|
||
[
|
||
{ $match: { age:{"$gt":13} } },
|
||
{ $sort: { age: 1 } },
|
||
{ $limit: 2 },
|
||
{ $group: { _id: "$age", "人数": { $sum: 1 } } },
|
||
]
|
||
)
|
||
|
||
aggregate默认返回分组信息_id,如果要去掉,可使用$project。
|
||
因为aggregate是按顺序处理的管道阶段操作器,所以管道的排序也很重要,下面两端代码使用相同的管道阶段操作器,但是不同的顺序,实现的效果也是不同的:
|
||
代码一:
|
||
db.student.aggregate(
|
||
[
|
||
{ $match: { age:{"$gt":13} } },
|
||
{ $sort: { age: 1 } },
|
||
{ $limit: 2 },
|
||
{ $group: { _id: "$age", "人数": { $sum: 1 } } }
|
||
]
|
||
)
|
||
|
||
|
||
代码二:
|
||
db.student.aggregate(
|
||
[
|
||
{ $match: { age:{"$gt":13} } },
|
||
{ $group: { _id: "$age", "人数": { $sum: 1 } } },
|
||
{ $sort: { _id: 1 } },
|
||
{ $limit: 2 }
|
||
]
|
||
)
|
||
```
|
||
|
||
## 7.性能监控
|
||
|
||
- db.stats(),查看当前数据库的状态,可看到数据库的名称,集合(表)数量,索引数量、大小,数据文件大小,存储空间大小和物理文件大小。
|
||
|
||
- db.serverCmdLineOpts(),查看启动参数
|
||
|
||
- db.serverStatus(),查询MongoDB的服务状态,有助于了解诊断和性能分析
|
||
|
||
```
|
||
serverStatus命令是静态的监控,MongoDB提供了动态的监控执行工具mongostat。
|
||
|
||
db.serverStatus().host # 主机名
|
||
db.serverStatus().locks # 锁信息
|
||
db.serverStatus().globalLock # 全局锁信息
|
||
db.serverStatus().mem # 内存信息
|
||
db.serverStatus().connections # 连接数信息
|
||
db.serverStatus().extra_info # 额外信息
|
||
db.serverStatus().indexCounters # 索引统计信息
|
||
db.serverStatus().backgroundFlushing # 后台刷新信息
|
||
db.serverStatus().cursors # 游标信息
|
||
db.serverStatus().network # 网络信息
|
||
db.serverStatus().repl # 副本集信息
|
||
db.serverStatus().opcountersRepl # 副本集的操作计数器
|
||
db.serverStatus().opcounters # 操作计数器
|
||
db.serverStatus().asserts # 断言信息Asserts
|
||
db.serverStatus().writeBacksQueued # writeBacksQueued
|
||
db.serverStatus().dur # 持久化(dur)
|
||
db.serverStatus().recordStats # 记录状态信息
|
||
db.serverStatus( { workingSet: 1 } ).workingSet # 工作集配置
|
||
db.serverStatus().metrics # 指标信息metrics
|
||
```
|
||
|
||
- mongostat,会动态输出一些serverStatus提供的重要信息,每秒输出一次。
|
||
|
||
```
|
||
mongostat会动态输出一些serverStatus提供的重要信息,每秒输出一次。
|
||
|
||
insert query update delete getmore command flushes mapped vsize res faults qrw arw net_in net_out conn time
|
||
*0 *0 *0 *0 0 11|0 0 0B 237M 15.0M 0 0|0 0|0 1.50k 22.7k 1 May 1 14:24:25.425
|
||
*0 *0 *0 *0 0 12|0 0 0B 237M 15.0M 0 0|0 0|0 1.55k 23.5k 1 May 1 14:24:26.405
|
||
*0 *0 *0 *0 0 11|0 0 0B 237M 15.0M 0 0|0 0|0 1.52k 23.0k 1 May 1 14:24:27.405
|
||
*0 *0 *0 *0 0 12|0 0 0B 237M 15.0M 0 0|0 0|0 1.52k 23.1k 1 May 1 14:24:28.404
|
||
*0 *0 *0 *0 0 11|0 0 0B 237M 15.0M 0 0|0 0|0 1.52k 23.0k 1 May 1 14:24:29.404
|
||
*0 *0 *0 *0 0 12|0 0 0B 237M 15.0M 0 0|0 0|0 1.53k 23.2k 1 May 1 14:24:30.396
|
||
|
||
|
||
insert、query、update、delete、getmore、command 每种对应操作的发生次数。
|
||
其中faults表示访问失败数,数据从内存交换出去,放到swap。值越小越好,最好不要大于100。
|
||
|
||
faults:查询从磁盘读取数据,标志服务器未达到最佳,所需的数据并未完全保存找内存中
|
||
qr/qw:队列等待的数目。
|
||
ar/aw:活动客户端的数目。
|
||
conn:打开的连接数。
|
||
flushes:数据刷写到磁盘的数目。
|
||
vsize:使用虚拟内存大小。
|
||
mapped:隐射的内存大小,约等于数据目录大小。
|
||
res:实际使用的内存大小
|
||
netId:表示通过网络传输进来的字节数。
|
||
netou:t表示通过网络传输出的字节数。
|
||
time:表示统计的时间。
|
||
```
|
||
|
||
- mongotop,查看哪个几个最繁忙
|
||
|
||
- db.currentOP(),可看到当前执行的进程,类似MySQL的show processlist
|
||
|
||
- show profile
|
||
|
||
```
|
||
db.setProfilingLevel(2) # enable profiling
|
||
db.system.profile.find() # show raw profile entries
|
||
show profile # 该命令可以查看最近的5条记录
|
||
该命令可以查看最近的5条记录:
|
||
ts:该命令在何时执行。
|
||
millis:执行耗时,以毫秒为单位。
|
||
op:什么操作。
|
||
query:设置的查询条件。
|
||
nReturned:返回的条数。
|
||
docsExamined:文档扫描条数。
|
||
|
||
# 清空还原profile集合使用命令:
|
||
db.setProfilingLevel(0)
|
||
db.system.profile.drop()
|
||
db.createCollection("system.profile", { capped: true, size:4000000 } )
|
||
db.setProfilingLevel(1)
|
||
```
|
||
|
||
## 8.备份和恢复
|
||
|
||
### 1).数据库备份和恢复
|
||
|
||
- mongodump导出数据库中全部的内容,使用-q参数增加查询条件,注意-q参数值的标点符号,否则会报错 too many positional arguments
|
||
|
||
```
|
||
mongodump --port 22400 -u "root" -p "123456" --authenticationDatabase "admin" -d test -o /home
|
||
mongodump --port 22400 -u "root" -p "123456" --authenticationDatabase "admin" -d test -c user -q "{name:'joe'}" -o /home
|
||
```
|
||
|
||
- mongorestore使用的数据文件就是mongodump备份的数据文件
|
||
|
||
```
|
||
# 使用/home路径下的BSON和JSON文件恢复数据库test,--drop参数表示如果已经存在test数据库则删除原数据库,去掉--drop则与原数据库合并
|
||
mongorestore --port 22400 -u "root" -p "123456" --authenticationDatabase "admin" -d test /home/test --drop
|
||
```
|
||
|
||
### 2).表的备份和恢复
|
||
|
||
- 导出json格式的备份文件,从test数据库中student集合到/home/test.json文件中
|
||
|
||
```
|
||
mongoexport --port 22400 -u "root" -p "123456" --authenticationDatabase "admin" -d test -c student -o /home/test.json
|
||
mongoexport --port 22400 -u "root" -p "123456" --authenticationDatabase "admin" -d test -c student -q "{name: 'joe'}" -o /home/test.json
|
||
```
|
||
|
||
- 导出csv格式的备份文件
|
||
|
||
```
|
||
# -f参数用于指定只导致id和name以及age字段,因为csv是表格类型的,所以对于内嵌文档太深的数据导出效果不是很好,所以一般来说会指定某些字段导出。
|
||
mongoexport --port 22400 -u "root" -p "123456" --authenticationDatabase "admin" -d test -c student --csv -f _id,name,age -o /home/test.csv
|
||
```
|
||
|
||
- json格式导入,使用备份文件/home/test.json导入数据到test数据库的student集合中
|
||
|
||
```
|
||
# --upsert表示更新现有数据,如果不使用—upsert则导入时已经存在的文档会报_id重复,数据不再插入。也可以使用--drop删除原数据。
|
||
mongoimport --port 22400 -u "root" -p "123456" --authenticationDatabase "admin" -d test -c student /home/test.json --upsert
|
||
```
|
||
|
||
- csv格式导入,--headerline指明不导入第一行,csv格式的文件第一行为列名
|
||
|
||
```
|
||
mongoimport --port 22400 -u "root" -p "123456" --authenticationDatabase "admin" -d test -c student --type csv --headerline --file /home/test.csv
|
||
```
|