Mongodb基础命令与用法

查看版本号

[root@VM_0_12_centos bin]# ./mongo -version
MongoDB shell version v3.6.5
git version: a20ecd3e3a174162052ff99913bc2ca9a839d618
OpenSSL version: OpenSSL 1.0.1e-fips 11 Feb 2013
allocator: tcmalloc
modules: none
build environment:distmod: rhel70distarch: x86_64target_arch: x86_64

查看
show dbs; 查看数据库,查看库占用空间
查找
db.tablename.find()  查找所有
使用
use databaseName 选库
show tables/collections 显示表
注意 system开头的表不要动
admin和Local这两个自带的库不要动
show databases; 个别版本可以使用
db.help(); 查看帮助
创建
mongodb是隐式创建数据库,直接use就能创建一个不存在的数据库。
use newdbName;
表也可以隐式创建。
db.goods.insert({_id:1,name:'NOKIAn86',price:29.9})
db.createCollection('user');  创建user表
插入
db.user.insert({name:'zhangsan',age:22});   插入数据
db.user.find();   查看user表数据,会查到一个主键,_id,也是主键,自动生成的
db.user.insert({_id:2,name:'poly',age:23});  指定主键的插入方式
mongodb可以插入格式不一样的文档格式
例如:
db.user.insert({_id:3,name:'hmm',hobby:['basketball','football'],intro:{'title':'my intro','content':'from china'}})
以上这种格式和之前的格式并不冲突,没有结构的特点。
删除
db.user.drop();  删除表
db.dropDatabase(); 删除库
增删改查:
需要传一个json对象。
修改:
语法:
db.collection.update(查询表达式,新值,选项)
db.table.update(匹配条件,新文档,true(upsert),true(修改多个值))
例:
db.news.update({name:'QQ'},{name:'MSN'});
查找news表中name值为QQ的文档,并将值改为msn,注意:这是替换,其他的值也会不见。
如果只想修改某一列,用$set关键字
db.collectionName.update(query,{$set:{name:'QQ'}})
$set 修改某列的值
$unset 删除某个列
$rename 重命名某个列
$inc 增长某个列
$setOnInsert 当upsert为true时,并发生了Isnert操作时,可以补充的字段。

在mongodb的命令交互界面中可以执行以下命令:

db   查看目前指向的数据库
还可以执行数学计算
x = 200
x / 5 ;
可以使用JavaScript标准库
Math.sin(Math.PI / 2);
new Date("2010/1/1");
"Hello,World".replace("World","Mongodb");

新建表

> post={"title":"My Blog Post","content":"Here's my blog post.","date":new Date()}
{
    "title" : "My Blog Post",
    "content" : "Here's my blog post.",
    "date" : ISODate("2018-07-06T02:35:57.716Z")
}
> db.blog.insert(post)
WriteResult({ "nInserted" : 1 })
> show collections;
blog
fuzzing_agent.configuration
system.users
system.version

定义一个字典
然后db.表名.insert(变量)
只查看一个文档:
findOne()
> db.blog.findOne();
{
    "_id" : ObjectId("5b3ed5c1de8e397067390e0d"),
    "title" : "My Blog Post",
    "content" : "Here's my blog post.",
    "date" : ISODate("2018-07-06T02:35:57.716Z")
}

find命令一次最多显示20个匹配的文档。
update
update需要两个参数,第一个是限定条件(老文档,被替换的),第二个是新的文档。
> post.comments = []
[ ]
> db.blog.update({title:"My Blog Post"},post)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.find()
{ "_id" : ObjectId("5b3ed5c1de8e397067390e0d"), "title" : "My Blog Post", "content" : "Here's my blog post.", "date" : ISODate("2018-07-06T02:35:57.716Z"), "comments" : [ ] }
>

删除
remove
db.blog.remove({title:"My Blog Post"})
修改
$set
需要用$修改器,如果不用,直接update({目标文档},{新文档}),会将原来的文档直接替换。
db.tester.update({"baz":0},{"$set":{"favorite book":"war and peace"}})
如果{"baz":0}这个字段中没有"favorite book"这个字段,则添加;有则修改
修改内嵌文档
例:
> db.blog.findOne();
{
    "_id" : ObjectId("5b431029f9cc01fb9708024b"),
    "title" : "A Blog Post",
    "content" : "...",
    "author" : {
        "name" : "joe",
        "email" : "joe@example.com"
    }
}

> db.blog.update({"author.name":"joe"},{"$set":{"author.name":"michel"}})
> db.blog.findOne();
{
    "_id" : ObjectId("5b431029f9cc01fb9708024b"),
    "title" : "A Blog Post",
    "content" : "...",
    "author" : {
        "name" : "michel",
        "email" : "joe@example.com"
    }
}

$inc增加某个键的数字值
例:
> db.games.findOne();
{
    "_id" : ObjectId("5b431235f9cc01fb9708024c"),
    "game" : "pinball",
    "user" : "tom"
}

> db.games.update({"user":"tom"},{"$inc":{"score":50}})             #没有则新建
注意,$inc必须是数字格式,用于整型,长整型,双精度浮点型,不能用于null,布尔型,数字构成的字符串
> db.games.findOne();
{
    "_id" : ObjectId("5b431235f9cc01fb9708024c"),
    "game" : "pinball",
    "user" : "tom",
    "score" : 50
}

$inc的用处如下:
> db.games.update({"user":"tom"},{"$inc":{"score":1000}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.games.findOne();
{
    "_id" : ObjectId("5b431235f9cc01fb9708024c"),
    "game" : "pinball",
    "user" : "tom",
    "score" : 1050
}

会将score这个值在原有50的基础上增加1000,改为1050
$push,向某个数组中添加元素
例:
> db.blog.findOne({"title":"A blog post"});
{
    "_id" : ObjectId("5b431538f9cc01fb9708024d"),
    "title" : "A blog post",
    "content" : "...",
    "commnet" : [
        {
            "name" : "joe",
            "email" : "joe@example.com",
            "content" : "nice post"
        }
    ]
}

之前没有commnet这个键值对,通过
> db.blog.update({"title" : "A blog post", "content" : "..."},{"$push":{"commnet":{"name":"joe","email":"joe@example.com","content":"nice post"}}})
增加,会生成commnet:[]这个格式。
在原有基础上,向commnet这个集合中添加内容:
> db.blog.update({"title":"A blog post"},{"$push":{"commnet":{"name":"michel","email":"michel@example.com","content":"good job"}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne({"title":"A blog post"});
{
    "_id" : ObjectId("5b431538f9cc01fb9708024d"),
    "title" : "A blog post",
    "content" : "...",
    "commnet" : [
        {
            "name" : "joe",
            "email" : "joe@example.com",
            "content" : "nice post"
        },
        {
            "name" : "michel",
            "email" : "michel@example.com",
            "content" : "good job"
        }
    ]
}

列表中的多了一个文档。
其他:
$each  可以通过一次push添加多个值
$slice slice必须是负数,限制包含最后加入的slice个数,比如-10,就会只保留最后添加的10个数,如果不够10个则全保留。
$sort 排序
注意,不能只将slice或sort与push配合使用,必须使用$each
$addToSet,可以避免添加重复内容:
db.users.update({"_id":ObjectId("123")},{"$addToSet":{"emails":"joe@gamil.com"}})
如上,添加joe@gamil的时候,会检查是否已经存在,如果已经存在则不变,不存在则添加
一次添加多个邮件地址,并去重:
db.users.update({"_id":ObjectId("123")},{"$addToSet":{"emails":{"$each":["joe@php.net","joe@example.com","joe@python.org"]}}})
$ne也是避免添加重复内容,在查找条件中写,效果不如addToSet
基于位置的数组修改器
通过数组的下标找到对应元素,下标从0开始。
db.blog.update({"post":"post_id"},{"$inc":{"comments.0.vates":1}})
如上,找到comments集合中下标为0的元素,将其vates+1
如果不知道下标位置,但知道需要更改的内容,可以通过一下方法修改:
db.blog.update({"comments.author":"John"},{"$set":{"comments.$.author":"jim"}})
如上,将已经匹配的John修改为jim,不知道下标则写$
修改器的速度
有的修改器速度比较快,如$inc,可以就地更改,不需要修改文档的大小,只需要改值。
有的会修改文档的大小,速度就会慢一些,$set能在文档大小不发生变化时立即修改,否则性能也会下降。
文档在插入Mongodb的时候,依次插入的文档会在磁盘上的位置是相邻的,因此如果一个文档变大了,原先的位置放不下了,这个文档就会被移动到集合的另一个位置。
比如
{"x":"a"}
{"x":"b"}
{"x":"c"}

将x:b改为x:bbbbbb
结果是
{"x":"a"}
{"x":"c"}
{"x":"bbbbb"}

填充因子
db.tablename.stats()
原理:
填充因子是Mongodb为每个新文档预留的增长空间,如果一个文档增大之后,填充因子会随之增加,当初没有多余空间的时候,文档会移动位置,然后之前的位置被填充因子覆盖,填充因子变大之后,所有的空间都会增加
到填充因子的大小,直到文档不在继续变大,之后,填充因子会缓慢变小。
填充因子的大小无法手动设置。
upsert
特殊的更新机制,如果没找到符合更新条件的文档,就会以这个条件和更新文档为基础,创建一个新的文档。
传统的修改方式:
js
> blog=db.analytics.findOne({"url":"/blog"})   #判断是否有这个文档
null
> if (blog){blog.pageviews++;db.analytics.save(blog);} else{db.analytics.save({"url":"/blog",pageviews:1})}    #如果有则+1,没有则保存
WriteResult({ "nInserted" : 1 })
> show tables;
analytics
blog
games
list
tester
> db.analytics.find();
{ "_id" : ObjectId("5b432c34f9cc01fb9708024f"), "url" : "/blog", "pageviews" : 1 }
>

使用upsert,既可以避免竞态问题,又可以缩减代码量,
第三个参数表示这个是upsert
db.analytics.update({"url":"/blog"},{"$inc":{"pageviews":1}},true)
作用和上面的一样,但是更高效,并且是原子性。
> db.users.update({"rep":25},{"$inc":{"rep":3}},true)
WriteResult({
    "nMatched" : 0,
    "nUpserted" : 1,
    "nModified" : 0,
    "_id" : ObjectId("5b432dc2764f0dcf8c8302cf")
})

如上,upsert创建一个rep值为25的文档,随后将这个值+3,最后得到28.
如果不加这个true,也就是不用upsert,update则匹配不到这个rep:25,然后就不会对集合进行任何更新。
如果再执行这条代码。则会在次创建一个文档,因为没有匹配到rep:25,唯一一个文档是rep:28
$setOnInsert
创建文档的同时并为他赋值,但是在之后的所有更新操作中,这个字段的值不在改变。
例:
> db.time.update({},{"$setOnInsert":{"createdAt":new Date()}},true)
WriteResult({
    "nMatched" : 0,
    "nUpserted" : 1,
    "nModified" : 0,
    "_id" : ObjectId("5b432f81764f0dcf8c8302dc")
})
> db.time.find();
{ "_id" : ObjectId("5b432f81764f0dcf8c8302dc"), "createdAt" : ISODate("2018-07-09T09:48:48.986Z") }
> db.time.update({},{"$setOnInsert":{"createdAt":new Date()}},true)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
> db.time.find();
{ "_id" : ObjectId("5b432f81764f0dcf8c8302dc"), "createdAt" : ISODate("2018-07-09T09:48:48.986Z") }
>

再次运行这个更新,会匹配到这个文档已存在,所以不会再插入文档,因此createdAt的值也不会改变。
同时更新多个文档
默认情况,更新只针对第一个匹配的文档执行操作,要是需要有多个文档符合条件并被更新,需要将Update的第四个参数设置为true。
> db.users.find();
{ "_id" : ObjectId("5b44117cf9cc01fb97080252"), "name" : "tom", "birthday" : "10/13/1991" }
{ "_id" : ObjectId("5b441194f9cc01fb97080253"), "name" : "jerry", "birthday" : "05/24/1993" }
{ "_id" : ObjectId("5b4411a6f9cc01fb97080254"), "name" : "mike", "birthday" : "10/13/1991" }
{ "_id" : ObjectId("5b4411bff9cc01fb97080255"), "name" : "michel", "birthday" : "03/14/1989" }
{ "_id" : ObjectId("5b4411d0f9cc01fb97080256"), "name" : "lucy", "birthday" : "10/13/1991" }

> db.users.update({"birthday":"10/13/1991"},{"$set":{"gift":"happy birthday!!!"}},false,true)
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })

> db.users.find();
{ "_id" : ObjectId("5b44117cf9cc01fb97080252"), "name" : "tom", "birthday" : "10/13/1991", "gift" : "happy birthday!!!" }
{ "_id" : ObjectId("5b441194f9cc01fb97080253"), "name" : "jerry", "birthday" : "05/24/1993" }
{ "_id" : ObjectId("5b4411a6f9cc01fb97080254"), "name" : "mike", "birthday" : "10/13/1991", "gift" : "happy birthday!!!" }
{ "_id" : ObjectId("5b4411bff9cc01fb97080255"), "name" : "michel", "birthday" : "03/14/1989" }
{ "_id" : ObjectId("5b4411d0f9cc01fb97080256"), "name" : "lucy", "birthday" : "10/13/1991", "gift" : "happy birthday!!!" }

如上,给users表生日为10/13/1991的人一个gift,效果如上。
删除
删除某个键
db.tester.update({"baz":1},{"$unset":{"favorite book":"Ender's Game"}})
删除baz:1这个条目的favorite book字典
删除数组中的元素
$pop
把数组看成队列,可以用$pop
{"$pop":{"key":1}} 从数组最后一个元素删除
{"$pop":{"key":-1}} 从数组第一个元素删除

$pull
根据条件删除数组元素
> db.list.insert({"todo":["dishes","laundry","dry cleaning"]})
WriteResult({ "nInserted" : 1 })
> db.list.find();
{ "_id" : ObjectId("5b431e50f9cc01fb9708024e"), "todo" : [ "dishes", "laundry", "dry cleaning" ] }

> db.list.update({},{"$pull":{"todo":"laundry"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.list.find();
{ "_id" : ObjectId("5b431e50f9cc01fb9708024e"), "todo" : [ "dishes", "dry cleaning" ] }

如上,删除了laundry
$pull会将所有匹配的文档删除,而不是只删除一个,对数组[1,1,2,1]执行Pull 1 则结果只剩2.
数组操作符只能用于包含数组值得键,例如,不能将一个整数插入数组,也不能将一个字符串从数组中弹出,要修改标量值,需要$set和$inc。
getLastError
检查最后一次操作中的错误。编写脚本的时候可能会用到。
db.runCommand({getLastError:1})
findAndModify
更新文档并返回被更新的文档
db.runCommand({"findAndModify":"processes","query":{"status":"READY"},"sort":{"priority":-1},"update":{"$set":{"status":"RUNNING"}}})
findAndModify的其他字段
query 查询文档,用于检索文档的条件
sort  排序结果的条件
update 修改文档,用于对匹配的文档进行更新
remove 布尔类型,表示是否删除文档
new 布尔类型,表示返回更新前还是更新后的文档,默认是更新前的文档
fields 文档中需要返回的字段
upsert   布尔类型,值为true表示upsert,默认为false
查询
查询条件
db.table.find(匹配条件,指定返回内容)
db.users.find({"name":"tom","age":27})    两个查询条件,条件1 and 条件2
指定返回内容
通过find或findOne的第二个参数来指定想要返回的键
db.users.find({},{"username":1,"email":1})
默认情况下,_id这个键是被返回的。
不希望返回_id的做法:
db.users.find({},{"username":1,"id":0})
如上返回了username,但是没有返回id
$lt =  '<'
$lte = '<='
$gt = '>'
$gte ='>='
$ne  不等于 <>
例:
db.users.find({"age":{"$gte":18,"$lte":30}})
如上查找大于等于18 and小于等于30的人
注意:
{"x":5}
{"x":15}
{"x":25}
{"x":[5,25]}
>db.test.find({"x":{"$gt":10,"$lt":20}})
{"x":15}
{"x":[5,25]}

如上,之所以会返回[5,25] 是因为25大于等于10,所以也一同返回了,
db.test.find({"x":{"$elemMatch":{"$gt":10,"$lt":20}}})
$elemMatch可以同时查询条件中两个语句与一个数组元素做比较,但是$elemMatch不会匹配非数组元素,所以在这里找不到任何匹配内容。
如果当前字段创建过索引,可以使用min()和max()将查询条件遍历的索引范围限制为$gt和$lt的值
>db.test.find({"x":{"$gt":10,"$lt":20}}).min({"x":10}).max({"x":20})
这种方法对日期也同样有用
例:
start=new Date("01/01/2007")
db.users.find({"registered":{"$lt":start}})

如上,查找01/01/2007以前注册的人。
$ne用法
db.users.find("username":{"$ne":"joe"})
查找名字不叫Joe的人
OR查询
$in
$or
$nin
$not
$in
例:
查找中奖号码是725,542,390的所有中奖文档。
db.raffle.find({"ticket_no":{"$in":[725,542,390]}})
例:
超找需要同时匹配id和用户名
db.users.find({"user_id":{"$in":[12345,"joe"]}})
如上,会匹配user_id是12345的,也会匹配user_id是joe的
$nin
与$in相反
例:
找到所有没中奖的人
db.raffle.find({"ticket_no":{"$nin":[725,542,390]}})
$or
例:
找到中奖的人
db.raffle.find({"$or":[{"ticket_no":725},{"winner":true}]})
如上,找到ticket_no为725的或者有winner为true的人
复杂一点的查找中奖人,结合$or和$in:
db.raffle.find({"$or":[{"ticket_no":{"$in":[725,542,390]}},{"winner":true}]})
如上,为查找ticket_no为725或542或390的,或者winner为true的人。
$or可以同时使用不同的查询条件,而$in只能或同样类型的条件。
$not
db.users.find({"id_num":{"$not":{"$mod":[5,1]}}})
如上$not为取反,$mod为取模
null
匹配null
如果直接通过"z":null,会将其他键不是z但值是null的也匹配出来,所以需要写成以下方式:
db.c.find({"z":{"$in":[null],"$exists":true}})
如上,匹配z的值为null的同时判断是否存在。
正则表达式
匹配名字为Joe或者joe的用户
db.users.find({"name":/joe/i})
Mongodb使用PCRE正则表达式库来匹配正则,可以先用js检查一下语法。
数组查询
数组元素查询和普通查询是一样的。
db.food.insert({"fruit":["apple","banana","peach"]})
查询:
db.food.find({"fruit":"banana"})
也能找到该条数据,效果如下(不合法):
{"fruit":"apple","fruit":"banana","furit":"peach"}
$all
匹配既有a也有b的,和and类似
> db.food.find();
{ "_id" : 1, "fruit" : [ "apple", "banana", "peach" ] }
{ "_id" : 2, "fruit" : [ "apple", "kumquat", "orange" ] }
{ "_id" : 3, "fruit" : [ "cherry", "banana", "apple" ] }

> db.food.find({"fruit":"apple","fruit":"banana"})
{ "_id" : 1, "fruit" : [ "apple", "banana", "peach" ] }
{ "_id" : 3, "fruit" : [ "cherry", "banana", "apple" ] }
> db.food.find({"fruit":{"$all":["apple","banana"]}})  
{ "_id" : 1, "fruit" : [ "apple", "banana", "peach" ] }
{ "_id" : 3, "fruit" : [ "cherry", "banana", "apple" ] }

如上第二个,是使用$all的写法,作用是匹配既有apple又有banana的情况。
第一种是我自己想的方法,效果是一样的。
$size
根据指定列表长度,来筛选符合列表长度的文档。
> db.food.find();
{ "_id" : 1, "fruit" : [ "apple", "banana", "peach" ] }
{ "_id" : 2, "fruit" : [ "apple", "kumquat", "orange" ] }
{ "_id" : 3, "fruit" : [ "cherry", "banana", "apple" ] }
{ "_id" : 4, "fruit" : [ "orange", "blueberry" ] }
> db.food.find({"fruit":{"$size":2}})
{ "_id" : 4, "fruit" : [ "orange", "blueberry" ] }

$slice
find的第二个参数是指定返回内容,配合$slice可以指定返回匹配数组元素的一个子集
例如:
db.blog.findOne(匹配条件,{"comments":{"$slice":10}})
如上,查找博客评论前10条评论
例如:
db.blog.findOne(匹配条件,{"comments":{"$slice":-10}})
如上,查找博客评论后10条评论
例如:
db.blog.findOne(匹配条件,{"comments":{"$slice":[23,10]}})
如上,查找评论集合第24-33的元素,23是指跳过前23个元素,10是指取10个元素。
注意,slice会默认返回除了指定子集的其他所有的键,比如_id,title什么的。
例如:
db.blog.find({"comments.name":"bob"},{"comments.$":1})
如上查找评论名为bob的数组元素,并取第一个,如果bob评论了多条也只返回第一个。
内嵌文档查询:
> db.score.findOne()
{
    "_id" : ObjectId("5b4468fef9cc01fb97080257"),
    "content" : "joe",
    "comments" : [
        {
            "author" : "joe",
            "score" : 3,
            "comment" : "nice post"
        },
        {
            "author" : "mary",
            "score" : 6,
            "comment" : "terrible post"
        }
    ]
}

查询mary分数在5分以上的评论
> db.score.find({"comments":{"$elemMatch":{"author":"mary","score":{"$gte":5}}}})
{ "_id" : ObjectId("5b4468fef9cc01fb97080257"), "content" : "joe", "comments" : [ { "author" : "joe", "score" : 3, "comment" : "nice post" }, { "author" : "mary", "score" : 6, "comment" : "terrible post" } ] }

$elemMatch将限定条件进行分组,仅当需要对一个内嵌文档的多个键操作时才会用到。
内嵌文档不能使用如下查找方式:
db.score.find({"comments":{"author":"mary","score":{"$gte":5}}})
内嵌文档的匹配必须整个文档完全匹配,这个查询不会匹配comments键

db.score.find({"comments.author":"mary","comments.score":{"$gte":5}})
符合author条件的评论和符合score条件的评论可能不是一个评论。

$where
$where可以后面使用javascript语句,所以尽量限制用户使用$where方式查询。
例子
> db.fooo.find();
{ "_id" : ObjectId("5b446d78f9cc01fb97080258"), "apple" : 1, "banana" : 6, "speach" : 3 }
{ "_id" : ObjectId("5b446d92f9cc01fb97080259"), "apple" : 8, "spinach" : 4, "watermelon" : 4 }

查找两个键具有相同值得文档,第二个文档中spinach和watermelon的值相同,所以应该返回它
> db.fooo.find({"$where":function(){for (var current in this){ for (var other in this){if (current != other && this[current] == this [other]){return  true ;}}}return false;}});
{ "_id" : ObjectId("5b446d92f9cc01fb97080259"), "apple" : 8, "spinach" : 4, "watermelon" : 4 }
>

$where查询比常规查询慢很多,而且有一定危险,所以尽量不用。
每个文档都要从BSON转换成JavaScript对象,然后通过$where表达式运行,而且$where不能使用索引。 
limit
>db.c.find().limit(3)
如上,限制返回结果为前三条
skip
db.c.find().skip(3)
如上,跳过前三条结果,如果集合里不足3条则不予显示
sort
db.stock.find().sort({username:1,age:-1})
如上,按照username升序及age降序排序
1为升序,-1为降序
组合使用:
db.stock.find({"desc":"mp3"}).limit(50).sort("price":-1)
如上,可以作为在线商店的分页使用,返回Mp3内容前50条,并按价格从高到低排序。
点击下一页后:
db.stock.find({"desc":"mp3"}).limit(50).skip(50).sort("price":-1)
注意,跳过过多会导致性能问题。
注意,不同类型的优先级:
默认如下:
1 最小值
2 null
3 数字
4 字符串
5 对象/文档
6 数组
7 二进制数据
8 对象ID
9 布尔型
10 日期
11 时间戳
12 正则表达式
13 最大值
索引
创建索引
> db.users.ensureIndex({"name":1})
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

如上,给username字段创建索引。
db.currentOp() 可以查看状态。
因为创建索引是有代价的,在插入更新删除的时候都要更耗费时间,还要更新集合所有的索引。所以Mongodb限制每个集合最多只能有64个索引。
通常在一个特定的集合上,不应该拥有2个以上的索引。
创建复合索引
db.users.ensureIndex({"age":1,"username":1})
复合索引在查询中有多个键,或者查询中有多个排序方向作用比较大。
索引嵌套文档
{
"username":"sid",
"loc":{
"ip":"1.2.3.4",
"city":"Springfield",
"state":"NY"
}
}

db.users.ensureIndex({"loc.city":1})
如上,给city字段建立索引,提高这个字段的查询速度。
注意:给内嵌文档创建索引和给内嵌文档的字段创建索引是不同的,除非查找整个内嵌文档,不然查找内嵌文档的某个字段的时候,内嵌文档的索引是没有作用的,需要建立字段索引。
数组索引
给数组创建索引相当于给数组中所有的元素创建索引,这样对数组的更改会比较耗时。
唯一索引
db.users.ensureIndex({"username":1},{"unique":true})
如上,给username设置了唯一索引,如果你插入两个同名的人就会报错。
_id也是唯一索引,区别是_id不能被删除,而其他唯一索引可以被删除。
强制唯一索引
在创建唯一索引的时候有时候会失败,因为已有的数据可能会有重复,但由于数据过多又不知道哪些数据重复,这个时候可以使用
dropDups
db.people.ensureIndex({"username":1},{"unique":true,"dropDups":true})
dropDups会强制删除重复的文档。慎用
查询计划
如果被查询的字段有多个索引,mongodb会从这个字段的索引子集中为每次查询计划选择一个,这些查询计划是并行执行的,最早返回100个结果的就会保留,其他的计划被终止。
查询计划会被缓存,这个查询以后会使用这条计划直到集合数据发生了比较大的变动。建立索引时或每执行1000次查询之后,查询优化器都会重新评估查询计划。
何时不应该使用索引
当数据比较少的时候,不使用索引反而比有索引快,因为使用索引需要先去索引表查找,再根据指针去数据表查找,需要找两次。
所有的索引都保存在system.index集合中,只能通过ensureIndex或者dropIndexes对其进行操作。
可以通过db.tablename.getIndexes()来查看这个表所有索引信息。
删除索引
db.people.dropIndex("x_1_y_1")
用索引描述信息里name字段的值来指定需要删除的索引。

数据类型
null
{"x":null}
布尔型
{"x":true}
数值
默认64位浮点数
{"x":3.14}
{"x":3}
整型
NumberInt表示4字节带符号整数
NumberLong表示8字符带符号整数
{"x":NumberInt("3")}
{"x":NumberLong("3")}
字符串
UTF-8字符串
{"x":"foobar"}
日期
毫秒数,不存储时区
{"x":new Date()}
正则表达式
使用正则表达式作为限定条件
{"x":/foorbar/i}
数组
{"x":["a","b","c"]}
内嵌文档
{"x":{"foo":"bar"}}
对象id
{"x":ObjectId()}
代码
{"x":function() {/*...*/}}
插入校验
所有文档都必须小于16MB。
批量插入脚本
for (var i=0 ;i<100; i++) {db.tester.insert({"foo":"bar","baz":i,"z":10-i})}

固定集合
固定集合相当于一个队列,如果固定集合已经满了,如果再向固定集合中添加内容,那么最老的文档会被删除。
固定集合不能被分片。
固定集合可以用于记录日志。
固定集合必须在使用之前显式创建。
db.createCollection("my_collection",{"capped":true,"size":100000})
如上方式创建固定集合,创建的固定集合叫my_collection,大小为100000字节,除了大小,固定集合还可以指定固定集合中文档的数量。
> db.createCollection("my_collection2",{"capped":true,"size":100000,"max":100});
{ "ok" : 1 }

固定集合创建之后就不能改变了。如果需要修改只能删除之后再重建。
创建固定集合的另一种方式,可以将常规集合转为固定集合。
db.runCommand({"convertToCapped":"test","size":10000})
test为集合名字。
无法将固定集合转为常规集合。只能删除重建。
自然排序
对于固定集合来说,自然排序就是从旧到新排序,也可以按照从新到旧排序。是按照文档的插入顺序排列的。
db.my_collection.find().sort({"$natural":-1})
创建没有_id索引的集合
如果在调用createCollection创建集合时指定autoIndexId选项为false,创建的集合就不会自动在_id上创建索引
一般不这么用,但是如果对只有插入操作的集合来说,效率会提升一些。
TTL索引
(time-to-live index)具有生命周期的索引。
这种索引允许为每一个文档设置一个超时时间,一个文档到达预期设置的超时时间后会被删除。这种类型的索引对于缓存问题非常有帮助。
db.foo.ensureIndex({"lastUpdated":1},{"expireAfterSecs":60*60*24})
如上,给lastUpdated字段建立了TTL索引,当服务器比对发现文件lastUpdated字段的时间晚expireAfterSecs秒时,文档就会被删除。
mongodb每分钟会对TTL索引进行一次清理。
聚合框架
用于对一连串的文档进行处理
包括:
管道(pipeline)
筛选(filtering)
投射(projecting)
分组(grouping)
排序(sorting)
限制(limiting)
跳过(skipping)
例如
找到发表文章最多的前五个作者
db.articles.aggregate({"$project":{"author":1}},{"$group":{"_id":"$author","count":{"$sum":1}}},{"$sort":{"count":-1}},{"$limit":5})
1 将每个文章中的作者投射出来
2 将作者按照名字排序,统计每个名字出现的次数
指定需要分组的字段author,这个操作完成后,每个作者只对应一个文档结果
3 将作者按照名字出现次数降序排列
4 将返回结果限制为前五个
aggregate()会返回一个文档数组。
$match
用于对文档集合进行筛选,筛选之后可以再对文档子集做聚合。
$match可以使用所有常规的查询操作符($gt,$lt$in等)
通常尽可能将$match放在管道的前面位置,好处1是可以快速将不需要的文档过滤掉,2是在投射分组之前执行match可以使用索引。
$project
使用$project可以从子文档中提取字段,可以重命名字段等等。
db.articles.aggregate({"$project":{"author":1,"_id":0}})
如上,可以只返回author字段内容,却不返回_id
将投射过的字段重命名
db.users.aggregate({"$project":{"userId":"$_id","_id":0}})
如上,将_id重命名为userId
注意需要将_id:0,不然这个字段会返回,也就是相当于返回两次,一个被重命名为userId
数学表达式
可以对数值做操作。
db.employees.aggregate({"$project":{"totalPay":{"$add":["$salary","$bonus"]}}})
如上,是将salary和bonus字段相加。
db.employees.aggregate({"$project":{"totalPay":{"$subtract":[{"$add":["$salary","$bonus"]},"$401k"]}}})
如上,是用salary+bonus-401k
操作符语法
"$add":[expr1,expr2]
这个操作符接收一个或多个表达式作为参数,将这些表达式相加。
"$subtract":[expr1,expr2]
接受两个参数,用第一个参数减去第二个参数作为结果。
"$multiply":[expr1,expr2...]
接收一个或多个表达式,将其相乘。
"$divide":[expr1,expr2]
接收两个表达式,用第一个表达式除以第二个表达式的商作为结果。
"$mod":[expr1,expr2]
接收两个表达式,将第一个表达式除以第二个表达式得到的余数作为结果。
日期表达式
$year
$month
$week
$dayOfMonth
$dayOfWeek
$dayOfYear
$hour
$minute
$second
只能对日期做操作,不能对数字做操作。
字符串表达式
"$substr":[expr,startOffset,numToReturn]
expr必须是字符串,startOffset字节开始到numToReturn字节。
"$concat":[expr1,expr2..]
将给定的字符串连接在一起作为结果返回。
"$toLower":expr
参数expr必须是个字符串,这个操作返回expr小写
"$toUpper":expr
参数expr必须是个字符串,这个操作返回expr大写
例如
db.employees.aggregate({"$project":{"email":{"$concat":[{"$substr":["$firstName",0,1]},".","$lastName","@example.com"]}}})
生成j.doe@example.com格式的例子。
逻辑表达式
"$cmp":[expr1,expr2]
如果expr1=expr2,返回0,如果expr1<2返回一个负数,如果expr1>expr2,返回一个正数
"$strcasecmp":[string1,string2]
比较string1和string2,区分大小写,只对罗马字符组成的字符串有效。
"$eq"/"$ne"/"$gt"/"$gte"/"$lt"/"$lte"
"$and"
"$or"  或
"$not"  取反
控制语句
"$cond":[booleanExpr,trueExpr,falseExpr]
如果booleanExpr为true,返回trueExpr,否则返回falseExpr
"$ifNull":[expr,replacementExpr]
如果expr是null,返回replacementExpr,否则返回expr。

转载于:https://www.cnblogs.com/ArmoredTitan/p/9309680.html

Mongodb基础命令与用法相关推荐

  1. MongoDB基础命令

    MongoDB 入门命令 查看当前数据库 > show dbs admin 0.000GB config 0.000GB local 0.000GB >-- use databaseNam ...

  2. Mongodb基础命令总结

    文章目录 1. MongoDB的安装与启动 2. 文档的操作 2.1 数据库的创建与删除 2.2 集合创建与删除 2.3 文档的增删改查 2.3.1 文档的插入(增) 2.3.2 文档的查询 2.3. ...

  3. MongoDB 基础用法及学习笔记

    MongoDB 基础用法 环境配置与安装 安装 查看MongoDB版本 启动MongoDB服务 检查服务状态 启动服务 打开配置文件,连接MongoDB 查看数据列表 退出 MongoDB 连接 Mo ...

  4. mongodb shell基础命令

    mongodb shell命令 1.数据库基本操作 在mongodb中,使用use来创建和选择数据库,当数据库不存在时,use会创建一个新的数据库,但是这数据库并没有持久化到硬盘里面,而存在内存中,只 ...

  5. MongoDB数据库(了解MongoDB及基础命令,备份数据库)

    文章目录 MongoDB数据库(了解MongDB及基础命令,备份数据库) 什么是MongoDB ? 主要特点 配置mongdb数据库 多实例配置 数据库操作 备份数据库 MongoDB数据库(了解Mo ...

  6. CentOS7上安装MongoDB及基础命令学习

    安装MongoDB 安装各个Linux平台依赖包 > ##Red Hat/CentOS > sudo yum install libcurl openssl > > ##Ubu ...

  7. MongoDB 的命令操作

    MongoDB 系列文章: MongoDB 的 yum 安装 MongoDB 的命令操作 MongoDB 的编程操作 在介绍 MongoDB 的具体操作和使用之前,有必要介绍一些 MongoDB 的基 ...

  8. shell常用的基础命令

    shell常用的基础命令 1 diff命令 2 patch命令 3 cut命令 4 sort命令 5 uniq 命令 6 tr命令 7 &&和 || 8 test命令 8.1 test ...

  9. linux常用基础命令操作收集

    linux常用基础命令操作收集,以下命令基于CentOs6.x 1.日常操作命令 **查看当前所在的工作目录 pwd **查看当前系统的时间 date **查看有谁在线(哪些人登陆到了服务器) who ...

最新文章

  1. docker 1.8.2 源代码编译
  2. 查看sqlserver版本
  3. 使用D9的SetFVF无法控制数据字段在内存中的顺序,所有字段的顺序都是固定的。自能选择好用还是不用。...
  4. 生命太短暂,我没时间讨厌你
  5. Java GUI简单点名器
  6. 计算机二级地15套题答案,计算机二级第15套答案解析.docx
  7. 2020年接近尾声,我选择来鲲鹏开发者技术峰会学点干货!
  8. 多线程暂停的一些方法区别
  9. QQ坦白说查看好友方法攻略
  10. linux默认超级用户密码,新手:ubuntu超级管理员的密码设置
  11. Dan Saks_const T vs T const
  12. 安卓开发 监听虚拟按键_Android 虚拟按键适配动态调整布局的方法
  13. 电气接点无线测温装置如何在中航光电新建厂房项目中应用
  14. 广州服务器哪个区最多,广州11区人口排行榜,最多人的区域竟是这!
  15. 解决坑----Unsupported major.minor version 51.0
  16. 关于对CC系列知识共享许可证【CC BY-SA 4.0】 的理解及整理
  17. autojs免root脚本引擎开发的微信群爆粉脚本免费开源分享代码
  18. 欧拉角的三维空间旋转
  19. 如何检索自然语言处理领域相关论文
  20. springboot项目结构

热门文章

  1. 苹果手机怎么关机?2个方法,教你快速关机
  2. java | (二十五)Servlet(1)req,resp,重定向,请求转发,数据共享
  3. python rarfile不支持中文路径_python使用zipfile解压文件中文乱码问题
  4. 中科曙光服务器操作系统安装指南,中科曙光云操作系统
  5. 与商超便利店巨头内卷“即时零售”
  6. linux开发亿连手机互联,亿连驾驶助手的汽车互联怎么用,亿连车机互联安装教程...
  7. 云顶之弈法机器人_云顶之弈里面出现了一个雷电法王,机器人一个勾自己没了!...
  8. 理解和应用单位化向量
  9. java实现电影购票项目(简单代码实现)
  10. 【框架】如何画出优秀的架构图