服务端启动/关闭
启动
./mongod
--port:指定服务器监听的端口号。默认27017
--dbpath: 数据存储目录。mongo默认数据库位置/data/db
--logpath:日志存储文件。默认输出到控制台
--logappend:在原日志文件上追加新日志;不加表示创建新的日志文件,原日志会更名保存在原日志位置。
--fork:以守护进程方式运行MongoDB,创建服务器进程。
--config:指定配置文件。
例:
以守护进程方式监听10000端口启动mongodb,数据存储在/data/mongodb目录下,日志存储在/data/monglog文件中。
./mongod --dbpath /data/mongodb --logpath /data/mongolog --logappend --port 10000 --fork
关闭
从服务端关闭 (ps axu|grep mongo 找到相应pid)
kill pid (SIGTERM)
kill -2 pid (SIGINT)
服务端收到SIGINT或SIGTERM,会正常关闭。
具体为:当前运行操作或者文件预分配完成,关闭所有打开的连接,将缓存刷新到磁盘上,最后停止。
kill -9 pid
会非正常关闭。因为数据库直接关闭,而没有完成上述步骤,会导致数据文件损坏。
从客户端关闭
> use admin
switched to db admin
> db.shutdownServer();
server should be down...
客户端连接
默认连接localhost:27017/test
./mongo
./mongo ip:port/dbname -u user -p password
数据库操作:
登录后默认数据库test
显示数据库列表
show dbs
显示当前数据库下集合列表
show collections
创建/切换 数据库
use dbname
查看当前数据库
db
删除当前所选数据库
db.dropdatabase
删除集合
db.runCommand({"drop":"collectionName"});
增删改查:
显示操作结果:
db.runCommand({"getLastError":1});
插入
db.collectionName.insert({"key":document});
删除
db.collectionName.remove({"key":document});
更新
//update 只能更新已存在的一条记录
db.collectionName.update({"key":document},{"key":new document});
//upsert 存在更新一条,不存在插入
db.collectionName,update({"key":document},{"key":new document},true);
//更新符合条件的多条记录
db.collectionName,update({"key":document},{"key":new document},false,true);
参数1:{"key":document},旧记录
参数2:{"key":new document},新记录
参数3:upsert,默认false,不存在是否插入
参数4:multi,默认false,是否更新全部匹配记录
查询
db.collectionName.find({"key":document});
//返回选择的列,显示col2、col3列
db.collectionName.find({"key":document},{"col1":0,"col2":1,"col3":1});
1、$lt、$lte、$gt、$gte、$ne
lte =less than equal
gte=greater than equal
ne=not equal
// 18<= age <25
db.collectionName.find({"age":{"$gte":18,"$lt":25}});
// 注册时间18年以前的
start=new Date("01/01/2018");
db.collectionName.find({"registerTime":{"$lt":start}});
2、$in、$nin、$or 与mysql中in、not in、or不同的是 值的类型可以不同
//查找name=H2o或age=20的人
//"H2o"与20类型不同
db.collectionName.find({"$or":[{"age":20},{"name":"H2o"}]});
//查找年龄为18、19、20、21、22、23的人
db.collectionName.find({"age":{"$in":[18,19,20,21,22,23]}});
3、$not、$mod 取余
//查找符合 x%5=1 的x 如:1,6,11
db.collectionName.find({"numbers":{"$mod":[5,1]}});
//查找符合 x%5!=1 的x 如:2,3,4,5,7,8,9,10
db.collectionName.find({"numbers":{"$not":{"$mod":[5,1]}}});
4、$exist
//查询到的结果为:sex==null 或者没有 sex字段的记录
db.collectionName.find({"sex":null});
//查询到的结果为:sex==null
db.collectionName.find({"sex":{"$in":[null],"$exist":true}});
5、正则表达式
//查询到 明朝那些事儿1、明朝那些事儿2、明朝那些事儿3等等
db.collectionName.find({"title":/明朝那些事儿?/});
6、数组 $all (全匹配)、$size(数组大小)、$slice(截取)
//arr下有value1与value2才匹配
db.collectionName.find({"arr":{"$all":["value1","value2"]}});
//arr大小为5则匹配
db.collectionName.find({"arr":{"$size":5}});
//查询{"key":document}下的arr的前10个
db.collectionName.find({"key":document},{"arr":{"$slice":10}});
//后10个
db.collectionName.find({"key":document},{"arr":{"$slice":-10}});
7、查询内嵌文档 $elemMatch
//查询key下面的key1=value1且key2>30 的记录
db.collectionName.find({"key":{"$elemeMatch":{"key1":"value1"},{"key2":{"$gt":30}}}});
8、$where(慢:每个文档从BSON转换成JavaScript对象,然后通过$where的表述式来运行)
//查询价格+10==100的记录
//以下两种写法等价
db.collectionName.find({"$where":"this.price+10==100"});
db.collectionName.find({"$where":function(){return this.price+10==100;}});
9、limit、skip、sort
//按price升序排序,跳过前两个,然后取10个。即取第3-12个。
// 1升序 -1降序
db.collectionName.find().skip(2).limit(10).sort({"price":1});
10、
db.collectionName.find({"key":"value"}).sort({"x":1});
//实际上执行时,shell会转化成
db.collectionName.find({"$query":{"key":"value"},"$orderby":{"x":1}});
11、findAndModify
query | 查询选择器,与findOne的查询选择器相同 |
update | 要更新的值,不能与remove同时出现 |
remove | 删除符合query条件的文档,不能与update同时出现 |
now | false:返回更改前的记录,true:返回更改后的记录。默认false。 |
upsert | 与update的upsert参数一样;有记录更新,无记录插入。 |
fields | 投影操作,与find的第二个参数一致(只返回设定的字段)。 |
sort | 排序条件,与sort函数的参数一致("sort":{"key":1升序|-1降序})。 |
db.COLLECTION_NAME.findAndModify({
query:{},
update:{},
remove:true|false,
new:true|false,
sort:{},
fields:{},
upsert:true|false
});
例:
将price=77的第一本书更改为price=75,并仅显示price字段 。返回更改前的数据。如果没有这样的记录则插入。
db.runCommand({"findAndModify":"book","query":{"price":77},"update":{"$set":{"price":75}},"fields":{"price":1},"new":false,"upsert":true});
聚合
1、count
//该集合下文档数量
db.collectionName.count();
//查询该集合下price==60的数量
db.collectionName.count({"price":60});
2、distinct
//查询collectionName集合下key的不同value
db.runCommand({"distinct":"collectionName","key":"value"});
3、group
key | 分组key |
initial | 初始化聚合结果文档变量 |
reduce | 一个聚合函数在分组期间的操作。该函数有两个参数:1-当前文档 2-聚合结果文档。 |
keyf | keyf与key必须有其中一个。把一个函数的返回值作为分组的key。该函数有一个参数:1-当前文档 |
cond | 过滤条件 |
finalize | 在返回最终结果之前,可以修改的结果文档或替换的结果文档作为一个整体。该函数有一个参数:1-聚合结果文档 |
原数据:
> db.book.find();
{ "_id" : ObjectId("5be53dcc301cbbc9bc68af26"), "title" : "地球往事", "price" : 50 }
{ "_id" : ObjectId("5be53ded301cbbc9bc68af27"), "title" : "三体-黑暗森林", "price" : 55 }
{ "_id" : ObjectId("5be53e3e301cbbc9bc68af28"), "title" : "三体-死神永生", "price" : 60 }
{ "_id" : ObjectId("5be553e8301cbbc9bc68af29"), "title" : "明朝那些事儿1", "price" : 50 }
{ "_id" : ObjectId("5be5595e301cbbc9bc68af2b"), "title" : "明朝那些事儿3", "price" : 50 }
{ "_id" : ObjectId("5be5662a059f962a6bd7d341"), "title" : "明儿", "price" : 90 }
按价格分组:
返回每组总价格、平均价格
db.book.group({
"key":{"price":true},
"initial":{"sumprice":0,"total":0},
"reduce":function(doc,res){res.sumprice+=doc.price;res.total+=1;},
"cond":{"price":{"$gte":50}},
"finalize":function(res){res.avg=res.sumprice/res.total;}
});
结果:
[
{
"price" : 50,
"sumprice" : 150,
"total" : 3,
"avg" : 50
},
{
"price" : 55,
"sumprice" : 55,
"total" : 1,
"avg" : 55
},
{
"price" : 60,
"sumprice" : 60,
"total" : 1,
"avg" : 60
},
{
"price" : 90,
"sumprice" : 90,
"total" : 1,
"avg" : 90
}
]
4、MapReduce
mongodb版本4.0.3
db.runCommand({
mapreduce:<collection>,
map:<mapfunction>,
reduce:<reducefunction>,
[,query:<query filter object>]
[,sort:<sorts the input objects using this key.Useful for optimization,like sorting by the emit key for fewer reduces>]
[,limit:<number of objects to return from collection>]
[,out:<see output options below>]
[,keeptemp:<true|false>]
[,finalize:<finalizefunction>]
[,scope:<object where fields go into javascript global scope>]
[, jsMode : boolean,default true]
[,verbose:true]
});
参数说明:
-
Mapreduce:要操作的目标集合
-
Map:映射函数(生成键值对序列,作为reduce函数参数)
-
Reduce:统计函数
-
Query:目标记录过滤
-
Sort:目标记录排序
-
Limit:限制目标记录数量
-
Out:统计结果存放集合(不指定使用临时集合,在客户端断开后自动删除)
-
Keeptemp:是否保留临时集合
-
Finalize:最终处理函数(对reduce返回结果进行最终整理后存入结果集合)
-
Scope:向map、reduce、finalize导入外部变量
-
jsMode说明:为false时 BSON-->JS-->map-->BSON-->JS-->reduce-->BSON,可处理非常大的mapreduce,为true时 BSON-->js-->map-->reduce-->BSON
-
Verbose:显示详细的时间统计信息
行查询的步骤
-
MapReduce对指定的集合Collection进行查询
-
对A的结果集进行mapper方法采集
-
对B的结果执行finalize方法处理
-
最终结果集输出到临时Collection中
-
断开连接,临时Collection删除或保留
参考:http://www.cnblogs.com/chenpingzhao/p/7913247.html
练习:
数据同group。
统计集合下所有字段的个数(不包含子字段)
map=function (){
for(var key in this){
emit(key,{count:1});
}
}
reduce=function(key,emits){
total=0;
for(var i in emits){
total+=emits[i].count;
}
return {"count":total};
}
例1:
> mr=db.runCommand({"mapreduce":"book","map":map,"reduce":reduce,"out":"outRes"});
{
"result" : "outRes",
"timeMillis" : 281,
"counts" : {
"input" : 6,
"emit" : 19,
"reduce" : 3,
"output" : 4
},
"ok" : 1
}
> db.outRes.find();
{ "_id" : "_class", "value" : { "count" : 1 } }
{ "_id" : "_id", "value" : { "count" : 6 } }
{ "_id" : "price", "value" : { "count" : 6 } }
{ "_id" : "title", "value" : { "count" : 6 } }
例2:只查询 price>50且按价格降序排列取前两个数据
mr=db.runCommand({
"mapreduce":"book",
"map":map,
"reduce":reduce,
"out":"outResQ",
"query":{"price":{"$gt":50}},
"sort":{"price":-1},
"limit":2,
"verbose":true
});
运行日志:
{
"result" : "outRes1",
"timeMillis" : 273,
"timing" : {
"mapTime" : 0,
"emitLoop" : 184,
"reduceTime" : 4,
"mode" : "mixed",
"total" : 273
},
"counts" : {
"input" : 2,
"emit" : 7,
"reduce" : 3,
"output" : 4
},
"ok" : 1
}
运行结果:
> db.outRes1.find();
{ "_id" : "_class", "value" : { "count" : 1 } }
{ "_id" : "_id", "value" : { "count" : 2 } }
{ "_id" : "price", "value" : { "count" : 2 } }
{ "_id" : "title", "value" : { "count" : 2 } }
索引
创建索引(1升序-1降序)
db.collectionName.ensureIndex({"key":1});
创建复合索引
db.collectionName.ensureIndex({"key":1,"key2":-1});
自定义索引名称
db.collectionName.ensureIndex({"key":1},{"name":"indexName"});
创建唯一索引
db.collectionName.ensureIndex({"key":1},{"name":"indexName"},{"unique":true});
创建唯一索引时,保留第一条记录,删除其他重复索引的记录(草率删除)
db.collectionName.ensureIndex({"key":1},{"name":"indexName"},{"unique":true,"dropDups":true});
explain 显示查询细节
有索引 与 无索引
> db.book.find({"title":"明儿"}).explain();
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "DemoDB.book",
"indexFilterSet" : false,
"parsedQuery" : {
"title" : {
"$eq" : "明儿"
}
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
//扫描索引
"stage" : "IXSCAN",
"keyPattern" : {
"title" : 1
},
//自定义的索引名称
"indexName" : "bookTitleIndex",
"isMultiKey" : false,
"multiKeyPaths" : {
"title" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"title" : [
"[\"明儿\", \"明儿\"]"
]
}
}
},
"rejectedPlans" : [ ]
}
}
> db.book.find({"price":90}).explain();
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "DemoDB.book",
"indexFilterSet" : false,
"parsedQuery" : {
"price" : {
"$eq" : 90
}
},
"winningPlan" : {
//扫描集合
"stage" : "COLLSCAN",
"filter" : {
"price" : {
"$eq" : 90
}
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
}
}
>
hint 强制使用指定索引
> db.book.ensureIndex({"price":1,"title":-1},{"name":"bookTitlePriceIndex"},{"unique":true});
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 2,
"numIndexesAfter" : 3,
"ok" : 1
}
//未指定强制使用的索引,会使用bookTitlePriceIndex索引,而拒绝使用bookTitleIndex索引
> db.book.find({"title":"明儿","price":90}).explain();
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "DemoDB.book",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"price" : {
"$eq" : 90
}
},
{
"title" : {
"$eq" : "明儿"
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"price" : 1,
"title" : -1
},
"indexName" : "bookTitlePriceIndex",
"isMultiKey" : false,
"multiKeyPaths" : {
"price" : [ ],
"title" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"price" : [
"[90.0, 90.0]"
],
"title" : [
"[\"明儿\", \"明儿\"]"
]
}
}
},
"rejectedPlans" : [
{
"stage" : "FETCH",
"filter" : {
"price" : {
"$eq" : 90
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"title" : 1
},
"indexName" : "bookTitleIndex",
"isMultiKey" : false,
"multiKeyPaths" : {
"title" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"title" : [
"[\"明儿\", \"明儿\"]"
]
}
}
}
]
},
"serverInfo" : {
"host" : "yangguangdeMacBook-Pro.local",
"port" : 10000,
"version" : "4.0.3",
"gitVersion" : "7ea530946fa7880364d88c8d8b6026bbc9ffa48c"
},
"ok" : 1
}
//强制使用bookTitleIndex索引
> db.book.find({"title":"明儿","price":90}).hint({"title":1}).explain();
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "DemoDB.book",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"price" : {
"$eq" : 90
}
},
{
"title" : {
"$eq" : "明儿"
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"filter" : {
"price" : {
"$eq" : 90
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"title" : 1
},
"indexName" : "bookTitleIndex",
"isMultiKey" : false,
"multiKeyPaths" : {
"title" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"title" : [
"[\"明儿\", \"明儿\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "yangguangdeMacBook-Pro.local",
"port" : 10000,
"version" : "4.0.3",
"gitVersion" : "7ea530946fa7880364d88c8d8b6026bbc9ffa48c"
},
"ok" : 1
数据库命令2
1、renameCollection 集合重命名
> show collections
DemoDb
book
demo1
demo2
demo3
demodb
outRes
outRes1
outResQ
> db.runCommand({"renameCollection":"demo3","to":"test3"});
{
"ok" : 0,
"errmsg" : "renameCollection may only be run against the admin database.",
"code" : 13,
"codeName" : "Unauthorized"
}
> use admin
switched to db admin
> db.runCommand({"renameCollection":"demo3","to":"test3"});
{
"ok" : 0,
"errmsg" : "Invalid namespace specified 'demo3'",
"code" : 73,
"codeName" : "InvalidNamespace"
}
> db.runCommand({"renameCollection":"DemoDB.demo3","to":"DemoDB.test3"});
{ "ok" : 1 }
> show collections
DemoDb
book
demo1
demo2
demodb
outRes
outRes1
outResQ
test3
2、buildInfo 返回服务器的版号和主机的操作系统
db.runCommand({"buildInfo":1});
3、collStats 返回指定集合的统计信息,包括数据大小、已分配的存储空间和索引的大小
db.runCommand({"collStats":"collectionName"});
4、distinct 列出指定集合中满足查询条件记录指定键的所有不同值
> db.runCommand({"distinct":"book","key":"price","query":{"price":{"$lt":90}}});
{ "values" : [ 49, 70, 80, 75, 76 ], "ok" : 1 }
> db.runCommand({"distinct":"book","key":"price","query":{"price":{"$lte":90}}});
{ "values" : [ 49, 70, 80, 90, 75, 76 ], "ok" : 1 }
5、drop 删除集合中所有数据
db.runCommand({"drop":"collectionName"});
6、dropDatabase 删除当前数据库的所有数据
db.runCommand({"dropDatabase":1});
7、dropIndexes 删除集合里面名称为indexName的索引(*则匹配所有索引)
db.runCommand({"dropIndexes":"collectionName","index":"indexName"});
8、isMaster 检查本服务器是主服务器还是从服务器
> db.runCommand({"isMaster":1});
{
"ismaster" : true,
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 100000,
"localTime" : ISODate("2018-11-17T08:07:07.757Z"),
"logicalSessionTimeoutMinutes" : 30,
"minWireVersion" : 0,
"maxWireVersion" : 7,
"readOnly" : false,
"ok" : 1
}
9、listCommands 列出所有可以在服务器上运行的命令及相关信息
db.runCommand({"listCommands":1});
10、listDatabasees 列出服务器上所有数据库
> db.runCommand({"listDatabases":1});
{
"ok" : 0,
"errmsg" : "listDatabases may only be run against the admin database.",
"code" : 13,
"codeName" : "Unauthorized"
}
> use admin
switched to db admin
> db.runCommand({"listDatabases":1});
11、ping 检查服务器连接是否正常(服务器上锁亦立即返回)
> db.runCommand({"ping":1});
{ "ok" : 1 }
12、repairDatabase 修复并压缩当前数据库(耗时)
db.runCommand({"repairDatabase":1});
13、serverStatus 返回这台服务器的管理统计信息
db.runCommand({"serverStatus":1});