MongoDB学习笔记6——高级查询
高级MongoDB特性是全文搜索、聚焦框架和MapReduce框架。
1)文本搜索
1-1)加载文本数据
$ mongoimport test.json -d test -c texttest (-d表示database,-c表示collection)
1-2)创建文本索引
use test;
db.texttest.createIndex({body:"text"});
db.texttest.getIndexes()
1-3)运行文本搜索命令
db.texttest.find({$text:{$search:"fish"}})
显示查询结果,值越大相关性越大
db.texttest.find({$text:{$search:"fish"}},{score:{$meta:"textScore"}})
1-4)过滤文本查询结果
db.texttest.find({$text:{$search:"fish"},about:"food"})
1-5)更复杂的文本搜索
db.texttest.find({$text:{$search:"cook"}},{_id:0,body:1}) (0表示不显示,1表示显示)
db.texttest.find({$text:{$search:"cook -lunch"}},{_id:0,body:1}) (从搜索中排除午餐)
db.texttest.find({$text:{$search:"mongodb test search"}}) (句子中含有mongodb test search即可匹配,不管是连续还是不连续)
db.texttest.find({$text:{$search:"\"mongodb test search\""}}) (句子中含有连续的mongodb test search才可以匹配)
1-6)额外的选项
db.texttest.find({$text:{$search:"fish"}}).limit(1)
db.texttest.find({$text:{$search:"fish",$language:"french"}}) (指定文本搜索所使用的语言)
1-7)其他语言中的文本索引
db.texttest.createIndex({body:"text"},{default_language:"french"})
注意事项:在每个集合上只能创建一个文本索引,所以在创建这个索引之前需要删除之前的文本索引。如果想要给集合中添加一个新的文本索引,就需要使用.dropIndex函数删除旧索引,其使用方式与使用createIndex函数相同。
此外。MongoDB允许在文档中指定自己的语言(english,french,spanish,swedish)
db.texttest.createIndex({content:"text"},{language_override:"lingvo"});
1-8)文本索引的复合索引
db.texttest.createIndex({content:"text",comments:"text"})
db.texttest.createIndex({"$**":"text"},{name:"alltextindex"})
设置权重:
db.texttest.createIndex({content:"text",comments:"text"},{weights:{content:10,comments:5}})
其中:相较于评论的权重5和内容的权重10,所有其他字段的默认权重都将是1。
使用非文本字段创建复合索引:
读出所有文档:
db.texttest.createIndex({content:"text",username:1})
db.texttest.find({$text:{$search:"fish"},about:"food"})explain("executionStates").executionStates;
在索引中添加about元素,可以避免出现读取所有文档的情况:
db.texttest.createIndex({about:1,body:"text"})
db.texttest.find({$text:{$search:"fish"},about:"food"})explain("executionStates").executionStates;
2)聚集框架
MongoDB中的聚集框架代表着在集合的数据上执行匹配、分组和转换操作的能力。可以使用的通配符:$group,$limit,$match,$sort,$unwind,$project,$skip,$out,$redact,$lookup
$ tar -xvf test.tgz
$ mongorestore test
db.aggregation.aggregate({pipeline document}) (创建聚集操作的通道流来实现)
2-1)$group
db.aggregation.aggregate({$group:{_id:"$color"}})
2-2)$sum
db.aggregation.aggregate({$group:{_id:"$color",count:{$sum:1}})
db.aggregation.aggregate($group:{_id:{color:"$color",transport:"$transport"},count:{$sum:1}})
2-3)$limit
db.aggregation.aggregate([$group:(_id:{color:"$color",transport:"$transport"},count:{$sum:1}}},{$limit:5}])
2-4)$match
db.aggregation.aggregate([{$match:{num:{$gt:500}}},{$group:(_id:{color:"$color",transport:"$transport"},count:{$sum:1}}},{$limit:5}])
2-5)$sort
db.aggregation.aggregate([{$group:{_id:{color:"$color",transport:"$transport"},count:{$sum:1}}},{$sort:{_id:1}},{$limit:5}])
2-6)$unwind
使用$unwind将接受一个数组并将每个元素分割到一个新的文档中(在内存中而不是添加到集合中)。
db.aggregation.aggregate({$unwind:"$vegetables"})
$project
db.aggregation.aggregate([{$unwind:"$vegetables"},{$project:{_id:0,fruits:1,vegetables:1}}])
2-7)$skip
db.aggregation.aggregate([{$unwind:"$vegetables"},{$project:{_id:0,fruits:1,vegetables:1}},{$skip:2995}])
2-8)$out
这个操作符允许把操作输出到集合中,而不是直接返回结果。
db.aggregation.aggregate([{$unwind:"$vegetables"},{$project:{_id:0,fruits:1,vegetables:1}},{$skip:2995}},{$out:"food"}])
2-9)$lookup
db.prima.insert({number:1,english:"one"})
db.prima.insert({number:2,english:"two"})
db.secunda.insert({number:1,ascii:49})
db.secunda.insert({number:2,ascii:50})
db.prima.aggregate([
{$lookup:{
from:"secunda",
localField:"number",
foreignField:"number",
as:"secundaDoc"
}},
])
简化输出:
db.prima.aggregate([
{$lookup:{
from:"secunda",
localField:"number",
foreignField:"number",
as:"secundaDoc"
}},
{$unwind:"$secundaDoc"},
{$project:{_id:"$number",english:1,ascii:"secundaDoc.ascii"}}
])
3)MapReduce
MapReduce通过两个JavaScript函数实现查询:map和reduce,这两个函数完全由用户自定义。map函数被设计用于生成键/值对。任何含有多个值的键都将输入到reduce函数中,reduce函数将返回输入数据的聚集结果。此后,还有一个可选的步骤,通过finalize函数对数据的显示进行完善。
3-1)使用map函数
var map = function(){
emit(this.color,this.num);
}
var reduce = function(color,numbers){};
将结果输出到控制台,将文档中out选项的值设置为{inline:1}
db.mapreduce.mapReduce(map,reduce,{out:{inline:1}})
将结果输出到集合mrresult中
var reduce = function(color,numbers){
return Array.sum(numbers);
}
db.mapreduce.mapReduce(map,reduce,{out:"mrresult"})
db.mrresult.findOne();
3-2)高级MapReduce
var map = function(){
var value = {
num : this.num,
count : 1
};
emit(this.color,value)
}
var reduce = function(color,val){
reduceValue = {num:0,count:0};
for(var i = 0; i < val.length; i++){
reduceValue.num += val[i].num;
reduceValue.count += val[i].count;
}
return reduceValue;
}
db.mapreduce.mapReduce(map,reduce,{out:"mrresult"})
db.mrresult.findOne();
var finailize = function(key,value){
value.avg = value.num / value.count;
return value;
}
db.mapreduce.mapReduce(map,reduce,{out:"mrresult",finalize:finalize})
db.mrresult.findOne()
3-3)调试MapReduce
如果出现某种问题,不理解函数中的内容,那么可以使用printjson()函数将JSON值输出到mongoDB日志文件中。
var emit = function(key,value){
print("emit result -key:" + key + "value:" + tojson(value));
}
map.apply(db.mapreduce.findOne())
a = [{"num":1,"count":1},{"num":2,"count":1},{"num":3,"count":1}]
reduce("blue",a)