周四脑袋发热,突然想获取文档中id的最大值,发现mongodb中没有sql中max聚合函数,只能通过对整个文档使用sort和limit(1)获取最大值。感觉很不
爽,突然想起map-reduce不就是聚合用的吗,于是乎就写了这个map-reduce的聚合功能。我的js一般,mongodb初学,很多东西没弄明白,我将实现方式和疑问在这里记录下来,
意识要和大家分享下,一是避免初学者和我犯同样的错误,而是希望有人解答我的疑问。
我在这里利用map-reduce主要实现了 max 和 sum 功能,其他功能的实现类似。直接上代码了
using MongoDB.Bson; using MongoDB.Driver; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace Mongo.Util { public static class Extension { /// <summary> /// 获取集合文档数量 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="collection"></param> /// <returns></returns> public static Dictionary<string, int> CountKeyOfCollection<T>(this MongoCollection<T> collection) { var map = @"function() {" + " for (var key in this) {" + " emit(key, { count : 1 });" + " }" + "}"; var reduce = @"function(key, emits) {" + " total = 0;" + " for (var i in emits) {" + " total += emits[i].count;" + " }" + " return { count : total };" + "}"; var finalize = @""; var mra = new MapReduceArgs(); mra.MapFunction = map; mra.ReduceFunction = reduce; var mr = collection.MapReduce(mra); Dictionary<string, int> dict = new Dictionary<string, int>(); foreach (var document in mr.GetResults()) { var json = document.ToJson(); JObject obj = JsonConvert.DeserializeObject<JObject>(json); var _id = obj["_id"]; var count = obj["value"]["count"]; dict.Add(_id.ToString(), Convert.ToInt32(count)); } return dict; } /// <summary> /// 这个错误,怎么获取当前key 的value /// </summary> /// <typeparam name="T"></typeparam> /// <param name="collection"></param> public static void Max<T>(this MongoCollection<T> collection) { //怎么获取当前key 的value var map = @"function(){ for(var key in this){ emit(key,value); } }"; var reduce = @"function(key,values){ var max=values[0]; var tmp; for(var i =1;i<values.lenght;i++) { tmp=values[i]; if(max<tmp) max=tmp; } return max; }"; var finalize = ""; var mra = new MapReduceArgs(); mra.MapFunction = map; mra.ReduceFunction = reduce; var mr = collection.MapReduce(mra); } /// <summary> /// 对指定key 求 max /// </summary> /// <typeparam name="T"></typeparam> /// <param name="collection"></param> /// <param name="field">key大小写敏感</param> public static void Max<T>(this MongoCollection<T> collection, string field) { var map = "function(){ " + "for(var key1 in this) " + " { " + " if(key1.toLowerCase()=='"+field.ToLower()+"')" + " {" + " emit(key1,this."+field+");" + " }" + " }" + " }"; var reduce = @"function(key,values){ var maxTmp=values[0]; for(var i=1;i<values.length;i++) { if(maxTmp<values[i]) maxTmp=values[i]; } return {key:key,max:maxTmp}; }"; var finalize = ""; var mra = new MapReduceArgs(); mra.MapFunction = map; mra.ReduceFunction = reduce; var mr = collection.MapReduce(mra); } /// <summary> /// 对指定key求和 /// /// </summary> /// <typeparam name="T"></typeparam> /// <param name="collection"></param> /// <param name="field">key大小写敏感</param> public static void Sum<T>(this MongoCollection<T> collection, string field) { var map = "function(){ " + "for(var key1 in this) " + " { " + " if(key1.toLowerCase()=='" + field.ToLower() + "')" + " {" + " emit(key1,this." + field + ");" + " }" + " }" + " }"; var reduce = @"function(key,values){ var ret= {key:key,sum:values.reduce(function(prev, cur, index, array){return prev + cur;})}; return ret; }"; var finalize = ""; var mra = new MapReduceArgs(); mra.MapFunction = map; mra.ReduceFunction = reduce; var mr = collection.MapReduce(mra); } /// <summary> /// 对指定key求和 /// 怎么判断value类型 $type=2 js判断方法 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="collection"></param> /// <param name="field">key大小写敏感</param> public static void Sum2<T>(this MongoCollection<T> collection, string field) { var map = "function(){ " + "for(var key1 in this) " + " { " + " if(key1.toLowerCase()=='" + field.ToLower() + "')" + " {" + " emit(key1,this." + field + ");" + " }" + " }" + " }"; var reduce = @"function(key,values){ var ret= {key:key,sum:Array.sum(values)}; return ret; }"; var finalize = ""; var mra = new MapReduceArgs(); mra.MapFunction = map; mra.ReduceFunction = reduce; var mr = collection.MapReduce(mra); } /// <summary> /// 这个错误,到底this 能获取什么 key value ???? /// </summary> /// <typeparam name="T"></typeparam> /// <param name="collection"></param> public static void Sum<T>(this MongoCollection<T> collection) { //关键问题怎么获取当前key 对应的value 怎么解决 var map = "function(){ " +"var i=0;" + "for(var key1 in this) " + " { " + " emit(key1,value[i]);" +"i++;" + " }" + " }"; var reduce = @"function(key,values){ var ret= {key:key,sum:values.reduce(function(prev, cur, index, array){return prev + cur;})}; return ret; }"; var finalize = ""; var mra = new MapReduceArgs(); mra.MapFunction = map; mra.ReduceFunction = reduce; var mr = collection.MapReduce(mra); } } }
注意:上边我说明错误的方法,是我希望高手指点的,这里只有max和sum方法能用,不要怀疑我的能力哦。
我想请教大家,map reduce中的this 到底是什么东东,当前文档,有什么属性可以使用, 我怎么看着当前key对应的value
参考学习资料:http://www.cnblogs.com/loogn/archive/2012/02/09/2344054.html
http://docs.mongodb.org/manual/reference/command/mapReduce/