Mongodb基礎命令與用法javascript
查看版本號php
[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: rhel70
distarch: x86_64
target_arch: x86_64
查看
查找
使用
show tables/collections 顯示錶
注意 system開頭的表不要動
admin和Local這兩個自帶的庫不要動
show databases; 個別版本可使用
建立
mongodb是隱式建立數據庫,直接use就能建立一個不存在的數據庫。
表也能夠隱式建立。
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'}})
以上這種格式和以前的格式並不衝突,沒有結構的特色。
刪除
增刪改查:
須要傳一個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須要兩個參數,第一個是限定條件(老文檔,被替換的),第二個是新的文檔。
[ ]
> 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",
}
}
> db.blog.update({"author.name":"joe"},{"$set":{"author.name":"michel"}})
> db.blog.findOne();
{
"_id" : ObjectId("5b431029f9cc01fb9708024b"),
"title" : "A Blog Post",
"content" : "...",
"author" : {
"name" : "michel",
}
}
$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",
"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",
"content" : "nice post"
},
{
"name" : "michel",
"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"}
填充因子
原理:
填充因子是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
如上,限制返回結果爲前三條
skip
如上,跳過前三條結果,若是集合裏不足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。