mongodb 高级操作:聚合,游标
一: 聚合有count,distinct,group,mapReduce。
1)count()函数:
Wed Jan 08 14:39:46.008 ReferenceError: clear is not defined
> db.person.count()
7
>
2)distinct():指定谁,谁就不能重复。
> db.person.distinct("age")
[ 23, 33, 43, 53 ]
> db.person.find(distinct("age"))
Wed Jan 08 14:43:55.057 ReferenceError: distinct is not defined
>
但是好像不能嵌套使用,哈哈哈。
3)group:group操作本质上形成了一种“k-v”模型,就像C#中的Dictionary,好,有了这种思维,
我们来看看如何使用group。下面举的例子就是按照age进行group操作,value为对应age的姓名。下面对这些参数介绍一下:
key:这个就是分组的key,我们这里是对年龄分组。
initial:每组都分享一个”初始化函数“,特别注意:是每一组,比如这个的age=20的value的list分享一个
initial函数,age=22同样也分享一个initial函数。
$reduce: 这个函数的第一个参数是当前的文档对象,第二个参数是上一次function操作的累计对象,第一次
为initial中的{”perosn“:[]}。有多少个文档, $reduce就会调用多少次。
> db.person.group({"key":{"age":true},"initial":{"person":[]},"$reduce":function(cur,prev){prev.person.push(cur.name)}})
[
{
"age" : 23,
"person" : [
"a",
"a",
"b",
"c"
]
},
{
"age" : 33,
"person" : [
"c"
]
},
{
"age" : 43,
"person" : [
"d"
]
},
{
"age" : 53,
"person" : [
"e"
]
}
]
>
①:想过滤掉age>25一些人员。
②:有时person数组里面的人员太多,我想加上一个count属性标明一下。
针对上面的需求,在group里面还是很好办到的,因为group有这么两个可选参数: condition 和 finalize。
condition: 这个就是过滤条件。
finalize:这是个函数,每一组文档执行完后,多会触发此方法,那么在每组集合里面加上count也就是它的活了。
> db.person.group({
... "key":{"age":true},
... "inital":{"person":[]},
... "reduce":function(doc,out){
... out.person.push(doc.name);
... },
... "finalize":function(out){
... out.count=out.person.length;
... },
... "condition":{"age":{$lt:33}}
... })
Wed Jan 08 16:11:28.466 group command failed: { "ok" : 0, "errmsg" : "initial has to be an object" } at src/mongo/shell/
db.js:655
> db.person.group({ "key":{"age":true}, "initial":{"person":[]}, "reduce":function(doc,out){ out.person.push(doc.name);
}, "finalize":function(out){ out.count=out.person.length; }, "condition":{"age":{$lt:33}} })
[
{
"age" : 23,
"person" : [
"a",
"a",
"b",
"c"
],
"count" : 4
}
]
>
4)mapreduce:mapReduce其实是一种编程模型,用在分布式计算中,其中有一个“map”函数,一个”reduce“函数。
① map:
这个称为映射函数,里面会调用emit(key,value),集合会按照你指定的key进行映射分组。
② reduce:
这个称为简化函数,会对map分组后的数据进行分组简化,注意:在reduce(key,value)中的key就是
emit中的key,vlaue为emit分组后的emit(value)的集合,这里也就是很多{"count":1}的数组。
③ mapReduce:
这个就是最后执行的函数了,参数为map,reduce和一些可选参数。
> map
Wed Jan 08 16:16:31.777 ReferenceError: map is not defined
> map
Wed Jan 08 16:16:43.399 ReferenceError: map is not defined
> map function(){
... emit(this.name,{count:1});
... }
Wed Jan 08 16:17:21.822 SyntaxError: Unexpected token function
> reduce
Wed Jan 08 16:17:38.873 ReferenceError: reduce is not defined
> db.person.mapReduce(map,reduce,{"out":"collection"})
Wed Jan 08 16:18:18.305 ReferenceError: map is not defined
> map
Wed Jan 08 16:19:25.495 ReferenceError: map is not defined
> map
Wed Jan 08 16:19:29.208 ReferenceError: map is not defined
> map .
... function(){
... emit(this.name,{count:1});
... }
Wed Jan 08 16:19:58.489 SyntaxError: Unexpected token {
> db.person.find()
{ "_id" : ObjectId("52ccf24c9a8355185b2af3df"), "name" : "a", "age" : 23, "gender" : "man" }
{ "_id" : ObjectId("52ccf2639a8355185b2af3e0"), "name" : "a", "age" : 23, "gender" : "women" }
{ "_id" : ObjectId("52ccf2769a8355185b2af3e1"), "name" : "b", "age" : 23, "gender" : "women" }
{ "_id" : ObjectId("52ccf27e9a8355185b2af3e2"), "name" : "c", "age" : 23, "gender" : "women" }
{ "_id" : ObjectId("52ccf2879a8355185b2af3e3"), "name" : "c", "age" : 33, "gender" : "women" }
{ "_id" : ObjectId("52ccf2949a8355185b2af3e4"), "name" : "d", "age" : 43, "gender" : "women" }
{ "_id" : ObjectId("52ccf29e9a8355185b2af3e5"), "name" : "e", "age" : 53, "gender" : "women" }
> map
Wed Jan 08 16:20:18.784 ReferenceError: map is not defined
>
一直报错,不知道为什么?
二>游标:
var list=db.person.find();
针对这样的操作,list其实并没有获取到person中的文档,而是申明一个“查询结构”,等我们需要的时候通过
for或者next()一次性加载过来,然后让游标逐行读取,当我们枚举完了之后,游标销毁,之后我们在通过list获取时,
发现没有数据返回了。
> list.forEach(function(x){)
... print(x.name);
... }
Wed Jan 08 16:29:19.707 SyntaxError: Unexpected token )
> var list=db.person.find();
> list.forEach(function(x){
... print(x.name);
... })
a
a
b
c
c
d
e
> list
> var list=db.person.find()
> list
{ "_id" : ObjectId("52ccf24c9a8355185b2af3df"), "name" : "a", "age" : 23, "gender" : "man" }
{ "_id" : ObjectId("52ccf2639a8355185b2af3e0"), "name" : "a", "age" : 23, "gender" : "women" }
{ "_id" : ObjectId("52ccf2769a8355185b2af3e1"), "name" : "b", "age" : 23, "gender" : "women" }
{ "_id" : ObjectId("52ccf27e9a8355185b2af3e2"), "name" : "c", "age" : 23, "gender" : "women" }
{ "_id" : ObjectId("52ccf2879a8355185b2af3e3"), "name" : "c", "age" : 33, "gender" : "women" }
{ "_id" : ObjectId("52ccf2949a8355185b2af3e4"), "name" : "d", "age" : 43, "gender" : "women" }
{ "_id" : ObjectId("52ccf29e9a8355185b2af3e5"), "name" : "e", "age" : 53, "gender" : "women" }
>
三>索引:
首先插入10w数据:
> db.person.remove();
> db.person.count();
0
> for(var i=0;i<100000;i++){
... var rand=parseInt(i.Math.random());
... db.person.insert({"name":"hxc","age":i})
... }
Wed Jan 08 16:38:40.489 TypeError: Cannot call method 'random' of undefined
> for(var i=0;i<100000;i++){
... var rand=parseInt(i*Math.random());
... db.person.insert({"name":"hxc","age":i})
... }
一:性能分析函数(explain)
好了,数据已经插入成功,既然我们要做分析,肯定要有分析的工具,幸好mongodb中给我们提供了一个关键字叫做“explain",那么怎么用呢?
还是看图,注意,这里的name字段没有建立任何索引,这里我就查询一个“name10000”的姓名。
> db.person.find({"name":"hxc"+10000}).explain()
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 100000,
"nscanned" : 100000,
"nscannedObjectsAllPlans" : 100000,
"nscannedAllPlans" : 100000,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 58,
"indexBounds" : {
},
"server" : "penghl:27017"
}
>
仔细看红色区域,有几个我们关心的key。
cursor: 这里出现的是”BasicCursor",什么意思呢,就是说这里的查找采用的是“表扫描”,也就是顺序查找,很悲催啊。
nscanned: 这里是10w,也就是说数据库浏览了10w个文档,很恐怖吧,这样玩的话让人受不了啊。
n: 这里是1,也就是最终返回了1个文档。
millis: 这个就是我们最最最....关心的东西,总共耗时114毫秒。
二:建立索引(ensureIndex)
> db.person.ensureIndex({"name":1})
> db.person.find({"name":"hxc"+10000}).explain()
{
"cursor" : "BtreeCursor name_1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 0,
"nscanned" : 0,
"nscannedObjectsAllPlans" : 0,
"nscannedAllPlans" : 0,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 6,
"indexBounds" : {
"name" : [
[
"hxc10000",
"hxc10000"
]
]
},
"server" : "penghl:27017"
}
可以看到,建立索引之后的查询只需要6毫秒。
这里我们使用了ensureIndex在name上建立了索引。”1“:表示按照name进行升序,”-1“:表示按照name进行降序。
看看这些敏感信息。
cursor: 这里出现的是”BtreeCursor",这么牛X,mongodb采用B树的结构来存放索引,索引名为后面的“name_1"。
nscanned: 我擦,数据库只浏览了一个文档就OK了。
n: 直接定位返回。
millis:
三:唯一索引:
建立唯一索引,重复的键值自然就不能插入,在mongodb中的使用方法是:
> db.person.remove()
> db.person.ensureIndex({"name":1},{"unique":true})
> db.person.insert({"name":"hxc","age":20})
> db.person.insert({"name":"hxc","age":20})
> db.person.remove()
> db.person.ensureIndex({"name":1},{"unique":true})
> db.person.insert({"name":"hxcc","age":20})
> db.person.insert({"name":"hxcc","age":20})
> db.person.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.person",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"name" : 1
},
"ns" : "test.person",
"name" : "name_1"
}
]
> db.person.dropIndexes("name_1")
{
"nIndexesWas" : 2,
"msg" : "non-_id indexes dropped for collection",
"ok" : 1
}
> db.person.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.person",
"name" : "_id_"
}
]
>
好像建不了唯一索引?
四:组合索引
有时候我们的查询不是单条件的,可能是多条件,比如查找出生在‘1989-3-2’名字叫‘jack’的同学,那么我们可以建立“姓名”和"生日“
的联合索引来加速查询。
> db.person.remove()
> db.person.count()
0
> db.person.insert({"name":"hxc","birthday":"1989-2-2"})
> db.person.insert({"name":"jack","birthday":"1989-3-2"})
> db.person.insert({"name":"joe","birthday":"1989-2-22"})
> db.person.insert({"name":"mary","birthday":"1989-3-12"})
> db.person.insert({"name":"jr","birthday":"1989-3-2"})
> db.person.ensureIndex({"name":1,"birthday":1})
> db.person.ensureIndex({"birthday":1,"name":1})
> db.person.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.person",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"name" : 1,
"birthday" : 1
},
"ns" : "test.person",
"name" : "name_1_birthday_1"
},
{
"v" : 1,
"key" : {
"birthday" : 1,
"name" : 1
},
"ns" : "test.person",
"name" : "birthday_1_name_1"
}
]
>
到底查询优化器会使用哪个查询作为操作:
> db.person.find({"name":"hxc","birthday":"1989-2-2"}).explain()
{
"cursor" : "BtreeCursor name_1_birthday_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 17,
"indexBounds" : {
"name" : [
[
"hxc",
"hxc"
]
],
"birthday" : [
[
"1989-2-2",
"1989-2-2"
]
]
},
"server" : "penghl:27017"
}
> db.person.find({"birthday":"1989-2-2","name":"jack"}).explain()
{
"cursor" : "BtreeCursor name_1_birthday_1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 0,
"nscanned" : 0,
"nscannedObjectsAllPlans" : 0,
"nscannedAllPlans" : 0,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"name" : [
[
"jack",
"jack"
]
],
"birthday" : [
[
"1989-2-2",
"1989-2-2"
]
]
},
"server" : "penghl:27017"
}
>
我们要相信查询优化器,它给我们做出的选择往往是最优的,因为我们做查询时,查询优化器会使用我们建立的这些索引来创建查询方案,
如果某一个先执行完则其他查询方案被close掉,这种方案会被mongodb保存起来,当然如果非要用自己指定的查询方案,这也是
可以的,在mongodb中给我们提供了hint方法让我们可以暴力执行。
> db.person.find({"birthday":"1989-2-2","name":"jack"}).hint("birthday":1,"name":1).explain()
Wed Jan 08 17:44:28.466 SyntaxError: Unexpected token :
> db.person.find({"birthday":"1989-2-2","name":"jack"}).hint({"birthday":1,"name":1}).explain()
{
"cursor" : "BtreeCursor birthday_1_name_1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 0,
"nscanned" : 0,
"nscannedObjectsAllPlans" : 0,
"nscannedAllPlans" : 0,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"birthday" : [
[
"1989-2-2",
"1989-2-2"
]
],
"name" : [
[
"jack",
"jack"
]
]
},
"server" : "penghl:27017"
}
>
五>删除索引:
可能随着业务需求的变化,原先建立的索引可能没有存在的必要了,可能有的人想说没必要就没必要呗,但是请记住,索引会降低CUD这三
种操作的性能,因为这玩意需要实时维护,所以啥问题都要综合考虑一下,这里就把刚才建立的索引清空掉来演示一下:dropIndexes的使用。
> db.person.dropIndexes()
{
"nIndexesWas" : 3,
"msg" : "non-_id indexes dropped for collection",
"ok" : 1
}
> db.person.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.person",
"name" : "_id_"
}
]
>
一: 聚合有count,distinct,group,mapReduce。
1)count()函数:
Wed Jan 08 14:39:46.008 ReferenceError: clear is not defined
> db.person.count()
7
>
2)distinct():指定谁,谁就不能重复。
> db.person.distinct("age")
[ 23, 33, 43, 53 ]
> db.person.find(distinct("age"))
Wed Jan 08 14:43:55.057 ReferenceError: distinct is not defined
>
但是好像不能嵌套使用,哈哈哈。
3)group:group操作本质上形成了一种“k-v”模型,就像C#中的Dictionary,好,有了这种思维,
我们来看看如何使用group。下面举的例子就是按照age进行group操作,value为对应age的姓名。下面对这些参数介绍一下:
key:这个就是分组的key,我们这里是对年龄分组。
initial:每组都分享一个”初始化函数“,特别注意:是每一组,比如这个的age=20的value的list分享一个
initial函数,age=22同样也分享一个initial函数。
$reduce: 这个函数的第一个参数是当前的文档对象,第二个参数是上一次function操作的累计对象,第一次
为initial中的{”perosn“:[]}。有多少个文档, $reduce就会调用多少次。
> db.person.group({"key":{"age":true},"initial":{"person":[]},"$reduce":function(cur,prev){prev.person.push(cur.name)}})
[
{
"age" : 23,
"person" : [
"a",
"a",
"b",
"c"
]
},
{
"age" : 33,
"person" : [
"c"
]
},
{
"age" : 43,
"person" : [
"d"
]
},
{
"age" : 53,
"person" : [
"e"
]
}
]
>
①:想过滤掉age>25一些人员。
②:有时person数组里面的人员太多,我想加上一个count属性标明一下。
针对上面的需求,在group里面还是很好办到的,因为group有这么两个可选参数: condition 和 finalize。
condition: 这个就是过滤条件。
finalize:这是个函数,每一组文档执行完后,多会触发此方法,那么在每组集合里面加上count也就是它的活了。
> db.person.group({
... "key":{"age":true},
... "inital":{"person":[]},
... "reduce":function(doc,out){
... out.person.push(doc.name);
... },
... "finalize":function(out){
... out.count=out.person.length;
... },
... "condition":{"age":{$lt:33}}
... })
Wed Jan 08 16:11:28.466 group command failed: { "ok" : 0, "errmsg" : "initial has to be an object" } at src/mongo/shell/
db.js:655
> db.person.group({ "key":{"age":true}, "initial":{"person":[]}, "reduce":function(doc,out){ out.person.push(doc.name);
}, "finalize":function(out){ out.count=out.person.length; }, "condition":{"age":{$lt:33}} })
[
{
"age" : 23,
"person" : [
"a",
"a",
"b",
"c"
],
"count" : 4
}
]
>
4)mapreduce:mapReduce其实是一种编程模型,用在分布式计算中,其中有一个“map”函数,一个”reduce“函数。
① map:
这个称为映射函数,里面会调用emit(key,value),集合会按照你指定的key进行映射分组。
② reduce:
这个称为简化函数,会对map分组后的数据进行分组简化,注意:在reduce(key,value)中的key就是
emit中的key,vlaue为emit分组后的emit(value)的集合,这里也就是很多{"count":1}的数组。
③ mapReduce:
这个就是最后执行的函数了,参数为map,reduce和一些可选参数。
> map
Wed Jan 08 16:16:31.777 ReferenceError: map is not defined
> map
Wed Jan 08 16:16:43.399 ReferenceError: map is not defined
> map function(){
... emit(this.name,{count:1});
... }
Wed Jan 08 16:17:21.822 SyntaxError: Unexpected token function
> reduce
Wed Jan 08 16:17:38.873 ReferenceError: reduce is not defined
> db.person.mapReduce(map,reduce,{"out":"collection"})
Wed Jan 08 16:18:18.305 ReferenceError: map is not defined
> map
Wed Jan 08 16:19:25.495 ReferenceError: map is not defined
> map
Wed Jan 08 16:19:29.208 ReferenceError: map is not defined
> map .
... function(){
... emit(this.name,{count:1});
... }
Wed Jan 08 16:19:58.489 SyntaxError: Unexpected token {
> db.person.find()
{ "_id" : ObjectId("52ccf24c9a8355185b2af3df"), "name" : "a", "age" : 23, "gender" : "man" }
{ "_id" : ObjectId("52ccf2639a8355185b2af3e0"), "name" : "a", "age" : 23, "gender" : "women" }
{ "_id" : ObjectId("52ccf2769a8355185b2af3e1"), "name" : "b", "age" : 23, "gender" : "women" }
{ "_id" : ObjectId("52ccf27e9a8355185b2af3e2"), "name" : "c", "age" : 23, "gender" : "women" }
{ "_id" : ObjectId("52ccf2879a8355185b2af3e3"), "name" : "c", "age" : 33, "gender" : "women" }
{ "_id" : ObjectId("52ccf2949a8355185b2af3e4"), "name" : "d", "age" : 43, "gender" : "women" }
{ "_id" : ObjectId("52ccf29e9a8355185b2af3e5"), "name" : "e", "age" : 53, "gender" : "women" }
> map
Wed Jan 08 16:20:18.784 ReferenceError: map is not defined
>
一直报错,不知道为什么?
二>游标:
var list=db.person.find();
针对这样的操作,list其实并没有获取到person中的文档,而是申明一个“查询结构”,等我们需要的时候通过
for或者next()一次性加载过来,然后让游标逐行读取,当我们枚举完了之后,游标销毁,之后我们在通过list获取时,
发现没有数据返回了。
> list.forEach(function(x){)
... print(x.name);
... }
Wed Jan 08 16:29:19.707 SyntaxError: Unexpected token )
> var list=db.person.find();
> list.forEach(function(x){
... print(x.name);
... })
a
a
b
c
c
d
e
> list
> var list=db.person.find()
> list
{ "_id" : ObjectId("52ccf24c9a8355185b2af3df"), "name" : "a", "age" : 23, "gender" : "man" }
{ "_id" : ObjectId("52ccf2639a8355185b2af3e0"), "name" : "a", "age" : 23, "gender" : "women" }
{ "_id" : ObjectId("52ccf2769a8355185b2af3e1"), "name" : "b", "age" : 23, "gender" : "women" }
{ "_id" : ObjectId("52ccf27e9a8355185b2af3e2"), "name" : "c", "age" : 23, "gender" : "women" }
{ "_id" : ObjectId("52ccf2879a8355185b2af3e3"), "name" : "c", "age" : 33, "gender" : "women" }
{ "_id" : ObjectId("52ccf2949a8355185b2af3e4"), "name" : "d", "age" : 43, "gender" : "women" }
{ "_id" : ObjectId("52ccf29e9a8355185b2af3e5"), "name" : "e", "age" : 53, "gender" : "women" }
>
三>索引:
首先插入10w数据:
> db.person.remove();
> db.person.count();
0
> for(var i=0;i<100000;i++){
... var rand=parseInt(i.Math.random());
... db.person.insert({"name":"hxc","age":i})
... }
Wed Jan 08 16:38:40.489 TypeError: Cannot call method 'random' of undefined
> for(var i=0;i<100000;i++){
... var rand=parseInt(i*Math.random());
... db.person.insert({"name":"hxc","age":i})
... }
一:性能分析函数(explain)
好了,数据已经插入成功,既然我们要做分析,肯定要有分析的工具,幸好mongodb中给我们提供了一个关键字叫做“explain",那么怎么用呢?
还是看图,注意,这里的name字段没有建立任何索引,这里我就查询一个“name10000”的姓名。
> db.person.find({"name":"hxc"+10000}).explain()
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 100000,
"nscanned" : 100000,
"nscannedObjectsAllPlans" : 100000,
"nscannedAllPlans" : 100000,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 58,
"indexBounds" : {
},
"server" : "penghl:27017"
}
>
仔细看红色区域,有几个我们关心的key。
cursor: 这里出现的是”BasicCursor",什么意思呢,就是说这里的查找采用的是“表扫描”,也就是顺序查找,很悲催啊。
nscanned: 这里是10w,也就是说数据库浏览了10w个文档,很恐怖吧,这样玩的话让人受不了啊。
n: 这里是1,也就是最终返回了1个文档。
millis: 这个就是我们最最最....关心的东西,总共耗时114毫秒。
二:建立索引(ensureIndex)
> db.person.ensureIndex({"name":1})
> db.person.find({"name":"hxc"+10000}).explain()
{
"cursor" : "BtreeCursor name_1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 0,
"nscanned" : 0,
"nscannedObjectsAllPlans" : 0,
"nscannedAllPlans" : 0,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 6,
"indexBounds" : {
"name" : [
[
"hxc10000",
"hxc10000"
]
]
},
"server" : "penghl:27017"
}
可以看到,建立索引之后的查询只需要6毫秒。
这里我们使用了ensureIndex在name上建立了索引。”1“:表示按照name进行升序,”-1“:表示按照name进行降序。
看看这些敏感信息。
cursor: 这里出现的是”BtreeCursor",这么牛X,mongodb采用B树的结构来存放索引,索引名为后面的“name_1"。
nscanned: 我擦,数据库只浏览了一个文档就OK了。
n: 直接定位返回。
millis:
三:唯一索引:
建立唯一索引,重复的键值自然就不能插入,在mongodb中的使用方法是:
> db.person.remove()
> db.person.ensureIndex({"name":1},{"unique":true})
> db.person.insert({"name":"hxc","age":20})
> db.person.insert({"name":"hxc","age":20})
> db.person.remove()
> db.person.ensureIndex({"name":1},{"unique":true})
> db.person.insert({"name":"hxcc","age":20})
> db.person.insert({"name":"hxcc","age":20})
> db.person.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.person",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"name" : 1
},
"ns" : "test.person",
"name" : "name_1"
}
]
> db.person.dropIndexes("name_1")
{
"nIndexesWas" : 2,
"msg" : "non-_id indexes dropped for collection",
"ok" : 1
}
> db.person.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.person",
"name" : "_id_"
}
]
>
好像建不了唯一索引?
四:组合索引
有时候我们的查询不是单条件的,可能是多条件,比如查找出生在‘1989-3-2’名字叫‘jack’的同学,那么我们可以建立“姓名”和"生日“
的联合索引来加速查询。
> db.person.remove()
> db.person.count()
0
> db.person.insert({"name":"hxc","birthday":"1989-2-2"})
> db.person.insert({"name":"jack","birthday":"1989-3-2"})
> db.person.insert({"name":"joe","birthday":"1989-2-22"})
> db.person.insert({"name":"mary","birthday":"1989-3-12"})
> db.person.insert({"name":"jr","birthday":"1989-3-2"})
> db.person.ensureIndex({"name":1,"birthday":1})
> db.person.ensureIndex({"birthday":1,"name":1})
> db.person.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.person",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"name" : 1,
"birthday" : 1
},
"ns" : "test.person",
"name" : "name_1_birthday_1"
},
{
"v" : 1,
"key" : {
"birthday" : 1,
"name" : 1
},
"ns" : "test.person",
"name" : "birthday_1_name_1"
}
]
>
到底查询优化器会使用哪个查询作为操作:
> db.person.find({"name":"hxc","birthday":"1989-2-2"}).explain()
{
"cursor" : "BtreeCursor name_1_birthday_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 17,
"indexBounds" : {
"name" : [
[
"hxc",
"hxc"
]
],
"birthday" : [
[
"1989-2-2",
"1989-2-2"
]
]
},
"server" : "penghl:27017"
}
> db.person.find({"birthday":"1989-2-2","name":"jack"}).explain()
{
"cursor" : "BtreeCursor name_1_birthday_1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 0,
"nscanned" : 0,
"nscannedObjectsAllPlans" : 0,
"nscannedAllPlans" : 0,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"name" : [
[
"jack",
"jack"
]
],
"birthday" : [
[
"1989-2-2",
"1989-2-2"
]
]
},
"server" : "penghl:27017"
}
>
我们要相信查询优化器,它给我们做出的选择往往是最优的,因为我们做查询时,查询优化器会使用我们建立的这些索引来创建查询方案,
如果某一个先执行完则其他查询方案被close掉,这种方案会被mongodb保存起来,当然如果非要用自己指定的查询方案,这也是
可以的,在mongodb中给我们提供了hint方法让我们可以暴力执行。
> db.person.find({"birthday":"1989-2-2","name":"jack"}).hint("birthday":1,"name":1).explain()
Wed Jan 08 17:44:28.466 SyntaxError: Unexpected token :
> db.person.find({"birthday":"1989-2-2","name":"jack"}).hint({"birthday":1,"name":1}).explain()
{
"cursor" : "BtreeCursor birthday_1_name_1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 0,
"nscanned" : 0,
"nscannedObjectsAllPlans" : 0,
"nscannedAllPlans" : 0,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"birthday" : [
[
"1989-2-2",
"1989-2-2"
]
],
"name" : [
[
"jack",
"jack"
]
]
},
"server" : "penghl:27017"
}
>
五>删除索引:
可能随着业务需求的变化,原先建立的索引可能没有存在的必要了,可能有的人想说没必要就没必要呗,但是请记住,索引会降低CUD这三
种操作的性能,因为这玩意需要实时维护,所以啥问题都要综合考虑一下,这里就把刚才建立的索引清空掉来演示一下:dropIndexes的使用。
> db.person.dropIndexes()
{
"nIndexesWas" : 3,
"msg" : "non-_id indexes dropped for collection",
"ok" : 1
}
> db.person.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.person",
"name" : "_id_"
}
]
>