前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅尝辄止MongoDB:高级查询

浅尝辄止MongoDB:高级查询

作者头像
用户1148526
发布2019-05-25 19:45:07
3K0
发布2019-05-25 19:45:07
举报
文章被收录于专栏:Hadoop数据仓库Hadoop数据仓库

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1433206

目录

一、全文检索

1. 建立索引

2. 执行搜索

二、聚合

三、MapReduce

1. 最简MapReduce

2. 求和

3. 求平均

4. 调试


一、全文检索

1. 建立索引

代码语言:txt
复制
    MongoDB一个集合上只能建立一个文本索引。
代码语言:txt
复制
    建立文本索引:在集合texttest上的body键上建立文本索引。
代码语言:javascript
复制
db.texttest.createIndex( { body : "text" } );
代码语言:txt
复制
    指定索引的默认语言:
代码语言:javascript
复制
db.texttest.createIndex( { body : "text" }, { default_language : "french" } );
代码语言:txt
复制
    在多种语言上建立索引:同一集合中存在多种语言,需要有一个字段标记每个文档的语言,如下面的四个文档中的lingvo字段标识其语言。
代码语言:javascript
复制
{ _id : 1, content : "cheese", lingvo : "english" }
{ _id : 2, content : "fromage", lingvo: "french" }
{ _id : 3, content : "queso", lingvo: "spanish" }
{ _id : 4, content : "ost", lingvo: "swedish" }
代码语言:txt
复制
    使用文档中给定的语言建立索引:
代码语言:javascript
复制
db.textExample.createIndex( { content : "text" }, { language_override : "lingvo" } );
代码语言:txt
复制
    建立符合索引:同时索引content和comments字段,可以在这两个字段上进行文本搜索。
代码语言:javascript
复制
db.textExample.createIndex( { content : "text", comments : "text" });
代码语言:txt
复制
    使用通配符:在全部字段上建立索引,并命名索引。
代码语言:javascript
复制
db.textExample.createIndex( { "$**": "text" }, { name: "alltextindex" } );
代码语言:txt
复制
    指定权重:指定content的权重是10,comments权重是5,其它字段的权重为1。
代码语言:javascript
复制
db.textExample.createIndex( { content : "text", comments : "text"}, { weights : { content: 10, comments: 5, } } );
代码语言:txt
复制
    同时建立文本和非文本的复合索引:content上建立文本索引,username上建立普通索引。
代码语言:javascript
复制
db.textExample.createIndex( { content : "text", username : 1 });

2. 执行搜索

代码语言:txt
复制
    文本搜索:以fish为词根进行搜索,返回body中匹配fish字符串的文档。
代码语言:javascript
复制
db.texttest.find({ $text : { $search :"fish" } });
代码语言:txt
复制
    过滤结果:在文本匹配的文档中过滤出about键值为food的结果。
代码语言:javascript
复制
db.texttest.find({ $text : { $search : "fish" }, about : "food" });
代码语言:txt
复制
    复杂搜索:返回文档中body键匹配cook,但不匹配lunch的body值。先搜索所有匹配条件的数据,再删除不匹配的数据。
代码语言:javascript
复制
db.texttest.find({ $text : { $search : "cook -lunch" } }, {_id:0, body:1});
代码语言:txt
复制
    字面搜索:返回body键匹配整个字符串mongodb text search,而不是匹配mongodb、text、search这三个单词的文档。
代码语言:javascript
复制
db.texttest.find({ $text : { search : "\"mongodb text search\"" } });
代码语言:txt
复制
    限制返回的文档数:返回1条。
代码语言:javascript
复制
db.texttest.find({ $text : { $search :"fish" }}).limit(1);
代码语言:txt
复制
    显示指定元素:只显示body。
代码语言:javascript
复制
db.texttest.find({ $text : { $search :"fish"}}, { _id : 0, body : 1 });
代码语言:txt
复制
    指定文本搜索使用的语言:全小写方式指定。
代码语言:javascript
复制
db.texttest.find({ $text : { $search :"fish", $language : " french" } });
代码语言:txt
复制
   利用文本与非文本的复合索引优化查询:
代码语言:javascript
复制
db.texttest.createIndex( { about : 1, body : "text" });
db.texttest.find({ $text : { $search : "fish"}, about : "food"}).explain("executionStats").executionStats;

二、聚合

代码语言:javascript
复制
db.collection.aggregate( { $group : { _id : "$color" } } );
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
select distinct color from collection;
-- 或
select color from collection group by color;
代码语言:javascript
复制
db.collection.aggregate({ $group : { _id : "$color", count : { $sum : 1 } } });
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
select color, count(1) count from collection group by color;
代码语言:javascript
复制
db.collection.aggregate({ $group : { _id : { color: "$color", transport: "$transport"} , count : { $sum : 1 } } });
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
select color transport, count(1) 
  from collection 
 group by color, transport;
代码语言:javascript
复制
db.collection.aggregate( 
    [
        { $group : { _id : { color: "$color", transport: "$transport"} , count : { $sum : 1 } } },
        { $limit : 5 }
    ]);
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
select color, transport, count(1) 
  from collection 
 group by color, transport 
 limit 5;
代码语言:javascript
复制
db.collection.aggregate( 
    [
        { $match : { num : { $gt : 500 } } },
        { $group : { _id : { color: "$color", transport: "$transport"} , count : { $sum : 1 } } },
        { $limit : 5 }
    ]);
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
select color, transport, count(1) 
  from collection 
 where num > 500
 group by color, transport 
 limit 5;
代码语言:javascript
复制
db.collection.aggregate( 
    [
        { $group : { _id : { color: "$color", transport: "$transport"} , count : { $sum : 1 } } },
        { $sort : { _id :1 } },
        { $limit : 5 }
    ]);
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
select color, transport, count(1) 
  from collection 
 group by color, transport 
 order by color, transport
 limit 5;
代码语言:javascript
复制
db.collection.aggregate( 
    [
        { $match : { num : { $gt : 500 } } },
        { $group : { _id : { color: "$color", transport: "$transport"} , count : { $sum : 1 } } },
        { $sort : { _id :1 } },
        { $limit : 1 }
    ]);
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
select color, transport, count(1) 
  from collection 
 where num > 500
 group by color, transport 
 order by color, transport
 limit 1;
代码语言:javascript
复制
db.collection.aggregate( { $unwind : "$vegetables" });
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
select collection.*, substring_index(substring_index(vegetables, ',', id),',' ,-1) vegetables
  from collection, nums -- nums为只有id一列的数字辅助表
 where id <= length(vegetables)-length(replace(vegetables,',',''))+1;
代码语言:javascript
复制
db.collection.aggregate(
    [
        { $unwind : "$vegetables" },
        { $project : { _id: 0, fruits:1, vegetables:1 } }
    ]);
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
select fruits, substring_index(substring_index(vegetables, ',', id),',' ,-1) vegetables
  from collection, nums -- nums为只有id一列的数字辅助表
 where id <= length(vegetables)-length(replace(vegetables,',',''))+1;
代码语言:javascript
复制
db.collection.aggregate(
    [
        { $unwind : "$vegetables" },
        { $project : { _id: 0, fruits:1, veggies: "$vegetables" } }
    ]);
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
select fruits, substring_index(substring_index(vegetables, ',', id),',' ,-1) veggies
  from collection, nums -- nums为只有id一列的数字辅助表
 where id <= length(vegetables)-length(replace(vegetables,',',''))+1;
代码语言:javascript
复制
db.collection.aggregate(
    [
        { $unwind : "$vegetables" },
        { $project : { _id: 0, fruits:1, vegetables:1 } },
        { $skip : 2995 }
    ]);
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
select fruits, substring_index(substring_index(vegetables, ',', id),',' ,-1) vegetables
  from collection, nums -- nums为只有id一列的数字辅助表
 where id <= length(vegetables)-length(replace(vegetables,',',''))+1
 limit 2995, 999999999;
代码语言:javascript
复制
db.collection.aggregate(
    [
        { $unwind : "$vegetables" },
        { $project : { _id: 0, fruits:1, vegetables:1 } },
        { $skip : 2995 },
        { $out : "food" }
    ]);
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
create table food as 
select @a:=@a+1 id, fruits, substring_index(substring_index(vegetables, ',', id),',' ,-1) vegetables
  from collection, (select @a:=0) t, nums -- nums为只有id一列的数字辅助表
 where id <= length(vegetables)-length(replace(vegetables,',',''))+1
 limit 2995, 999999999; 
代码语言:javascript
复制
db.prima.aggregate(
    [
        {$lookup: {
            from : "secunda",
            localField : "number",
            foreignField : "number",
            as : "secundaDoc"
         } },
    ]);
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
select prima.*, concat(secunda.c1,secunda.c2,...secunda.cn) secundaDoc
  from prima left join secunda on prima.number = secunda.number;
代码语言:javascript
复制
db.prima.aggregate(
    [
        {$lookup:{
            from : "secunda",
            localField : "number",
            foreignField : "number",
            as : "secundaDoc" }},
        {$unwind: "$secundaDoc"},
        {$project: {_id : "$number", english:1, ascii:"$secundaDoc.ascii" }}
    ]);
代码语言:txt
复制
    类比SQL:
代码语言:javascript
复制
select prima.*, secunda.*
  from prima left join secunda on prima.number = secunda.number;

三、MapReduce

代码语言:txt
复制
    MongoDB通过两个用户自定义的JavaScript函数实现查询:map和reduce。MongoDB将对指定的集合执行一个专门的查询,所有匹配该查询的文档都将被输入到map函数中。map函数被设计用于生成键值对。任何含有多个值的键都将被输入到reduce函数中,reduce函数将返回输入数据的聚合结果。最后,还有一个可选步骤,通过finalize函数对数据的显示进行完善。
代码语言:txt
复制
    以下是来自文档的图,可以清楚的说明 Map-Reduce 的执行过程。

1. 最简MapReduce

代码语言:txt
复制
    定义map函数:
代码语言:javascript
复制
var map = function() {
    emit(this.color, this.num);
};
代码语言:txt
复制
    MongoDB中使用emit函数向MapReduce提供Key/Value对。map函数接收集合中的color和num字段作为输入,输出为以color为键,以num数组为值的文档。
代码语言:txt
复制
    定义空reduce函数:
代码语言:javascript
复制
var reduce = function(color, numbers) { };
代码语言:txt
复制
    reduce函数接收map传来的键值对,但不执行任何操作。
代码语言:txt
复制
    执行MapReduce:
代码语言:javascript
复制
db.mapreduce.mapReduce(map,reduce,{ out: { inline : 1 } });
代码语言:txt
复制
    { out : { inline : 1 } } 表示将执行结果输出到控制台,显示类似如下的结果。
代码语言:javascript
复制
{
    "results" : [
        {
            "_id" : "black",
            "value" : null
        },
        {
            "_id" : "blue",
            "value" : null
        },
        ...
        {
            "_id" : "yellow",
            "value" : null
        }
    ],
    "timeMillis" : 95,
    "counts" : {
        "input" : 1000,
        "emit" : 1000,
        "reduce" : 55,
        "output" : 11
    },
    "ok" : 1,
}
代码语言:txt
复制
    结果显示,为每种颜色创建了一个单独的文档,并且使用颜色作为文档的唯一\_id值。因为reduce函数体为空,所以value被设置为null。

2. 求和

代码语言:txt
复制
    定义求和reduce函数:
代码语言:javascript
复制
var reduce = function(color, numbers) {
    return Array.sum(numbers);
};
代码语言:txt
复制
    该reduce函数对每个color对应的多个num求和。
代码语言:txt
复制
    执行MapReduce,并将结果输出到集合mrresult中:
代码语言:javascript
复制
db.mapreduce.mapReduce(map,reduce,{ out: "mrresult" });
代码语言:txt
复制
    查看结果集合:
代码语言:javascript
复制
> db.mrresult.findOne();
{ "_id" : "black", "value" : 45318 }

3. 求平均

代码语言:txt
复制
    map函数:
代码语言:javascript
复制
var map = function() {
    var value = {
        num : this.num,
        count : 1
    };
    emit(this.color, value);
};
代码语言:txt
复制
    count为计数器,为了只统计每个文档一次,将count值设置为1。
代码语言:txt
复制
    reduce函数:
代码语言:javascript
复制
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;
};
代码语言:txt
复制
    用一个简单的循环对num和count求和。注意reduce函数中return函数返回的值,必须与map函数中发送到emit函数中的value结构相同。
代码语言:txt
复制
    finalize函数:
代码语言:javascript
复制
var finalize = function (key, value) {
    value.avg = value.num/value.count;
    return value;
};
代码语言:txt
复制
    finalize函数从reduce函数接收结果,并计算平均值。
代码语言:txt
复制
    执行:
代码语言:javascript
复制
db.mapreduce.mapReduce(map,reduce,{ out: "mrresult", finalize : finalize });
代码语言:txt
复制
    查看结果:
代码语言:javascript
复制
> db.mrresult.findOne();
{
    "_id" : "black",
    "value" : {
        "num" : 45318,
        "count" : 91,
        "avg" : 498
    }
}

4. 调试

(1)调试map函数

代码语言:txt
复制
     重载emit函数,打印map函数的输出:
代码语言:javascript
复制
var emit = function(key, value) {
    print("emit results - key: " + key + " value: " + tojson(value));
}
代码语言:txt
复制
    使用map.apply和样例文档进行测试:
代码语言:javascript
复制
> map.apply(db.mapreduce.findOne());
emit results - key: blue value: { "num" : 1, "count" : 1 }

(2)调试reduce函数

代码语言:txt
复制
     首先需要确认map和reduce函数返回结果的格式必须严格一致。然后创建一个数组,模拟传入到reduce函数中的数组:
代码语言:javascript
复制
a = [{ "num" : 1, "count" : 1 },{ "num" : 2, "count" : 1 },{ "num" : 3, "count" : 1 }]
代码语言:txt
复制
    现在调用reduce函数,显示返回结果:
代码语言:javascript
复制
>reduce("blue",a);
{ "num" : 6, "count" : 3 }
代码语言:txt
复制
    如果出现某些问题,不理解函数中的内容,那么可以使用printjson()函数将JSON值输出到mongodb日志文件中。在调试时,这是一个有价值的工具。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年10月09日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、全文检索
    • 1. 建立索引
      • 2. 执行搜索
      • 二、聚合
      • 三、MapReduce
        • 1. 最简MapReduce
          • 2. 求和
            • 3. 求平均
              • 4. 调试
              相关产品与服务
              云数据库 MongoDB
              腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档