开门见山,20%是我造的,哈哈,为的就是让各位mongoer可以对db.system.js collection 引发注意。javascript
这个也是在我最近浏览InfoQ 的时候,看到一篇关于MongoDB 文章1的时候意识到的问题,随后和开发们沟通了下,结果是对这个collection 不是很了解,遂生此文。java
先来看下官文给出的解释:linux
<database>.system.js
The<database>.system.js
collection holds special JavaScript code for use in server side JavaScript. See Store a JavaScript Function on the Server for more information.mongodb
解释很简单,立刻就进入实操环节shell
db.system.js.save( { _id: "echoFunction", value : function(x) { return x; } } )
可是并无任何效果,shell里表示,echoFunction undefined. json
在查看 db.system.js
确实有一条记录segmentfault
> db.system.js.find({_id: 'echoFunction'}).pretty() { "_id" : "echoFunction", "value" : { "code" : "function (x) { return x; }" } }
继续查看doc,原来还须要经过 loadServerScripts
函数 load 进数据字典,这个操做就有点像咱们在linux 环境中 source ~/.bash_profile 同样了。bash
执行一次,db.loadServerScripts()
, 果真就可使用咱们自定义的函数了。ide
那问题来了,如何提高咱们的工做效率呢?函数
在MongoDB 中,虽然有 $sum
, $avg
等一系列的pipeline,可是,对于DBA也好,Developer 也罢,许多的报表、统计aggregation 并不能彻底代劳,mapReduce 就是为了这个时候而上的,那每次都要去写一个function 去 sum,去 avg 总显得在反复造轮子,所以咱们彻底能够在这种状况下,在 db.system.js
中加入咱们经常使用的统计函数,好比 sum
, avg
, max
, min
等等。
这里我就给出本身经常使用的函数供你们参考:
db.system.js.save( { _id : "Sum" , value : function(key,values) { var total = 0; for(var i = 0; i < values.length; i++) total += values[i]; return total; }});
db.system.js.save( { _id : "Avg" , value : function(key,values) { var total = Sum(key,values); var mean = total/values.length; return mean; }});
db.system.js.save( { _id : "Max" , value : function(key,values) { var maxValue=values[0]; for(var i=1;i<values.length;i++) { if(values[i]>maxValue) { maxValue=values[i]; } } returnmaxValue; }});
db.system.js.save( { _id : "Min" , value : function(key,values) { var minValue=values[0]; for(var i=1;i<values.length;i++) { if(values[i]<minValue) { minValue=values[i]; } } return minValue; }});
db.system.js.save( { _id : "Variance" , value : function(key,values) { var squared_Diff = 0; var mean = Avg(key,values); for(var i = 0; i < values.length; i++) { var deviation = values[i] - mean; squared_Diff += deviation * deviation; } var variance = squared_Diff/(values.length); return variance; }});
db.system.js.save( { _id : "Standard_Deviation" , value : function(key,values) { var variance = Variance(key,values); return Math.sqrt(variance); }});
那么接下来咱们就用Map-Reduce来结合以前的自定义聚合函数来作详解。(这里权当各位大佬熟悉Map-Reduce了)
{ "_id" : ObjectId("4f7be0d3e37b457077c4b13e"), "_class" : "com.infosys.mongo.Sales", "orderId" : 1, "orderDate" : "26/03/2011", "quantity" : 20, "salesAmt" : 200, "profit" : 150, "customerName" : "CUST1", "productCategory" : "IT", "productSubCategory" : "software", "productName" : "Grad", "productId" : 1 } { "_id" : ObjectId("4f7be0d3e37b457077c4b13f"), "_class" : "com.infosys.mongo.Sales", "orderId" : 2, "orderDate" : "23/05/2011", "quantity" : 30, "salesAmt" : 200, "profit" : 40, "customerName" : "CUST2", "productCategory" : "IT", "productSubCategory" : "hardware", "productName" : "HIM", "productId" : 1 } { "_id" : ObjectId("4f7be0d3e37b457077c4b140"), "_class" : "com.infosys.mongo.Sales", "orderId" : 3, "orderDate" : "22/09/2011", "quantity" : 40, "salesAmt" : 200, "profit" : 80, "customerName" : "CUST1", "productCategory" : "BT", "productSubCategory" : "services", "productName" : "VOCI", "productId" : 2 } { "_id" : ObjectId("4f7be0d3e37b457077c4b141"), "_class" : "com.infosys.mongo.Sales", "orderId" : 4, "orderDate" : "21/10/2011", "quantity" : 30, "salesAmt" : 200, "profit" : 20, "customerName" : "CUST3", "productCategory" : "BT", "productSubCategory" : "hardware", "productName" : "CRUD", "productId" : 2 } { "_id" : ObjectId("4f7be0d3e37b457077c4b142"), "_class" : "com.infosys.mongo.Sales", "orderId" : 5, "orderDate" : "21/06/2011", "quantity" : 50, "salesAmt" : 200, "profit" : 20, "customerName" : "CUST3", "productCategory" : "BT", "productSubCategory" : "hardware", "productName" : "CRUD", "productId" : 1 }
db.system.js.save({ _id : "Sum" , value: function(key,values) { var total = 0; for(var i = 0; i < values.length; i++) total += values[i]; return total; } });
db.runCommand( { mapreduce: "sales" , map: function() { emit({ key0:this.productCategory, key1:this.productSubCategory, key2:this.productName }, this.salesAmt ); }, reduce: function(key, values) { var result = Sum(key, values); return result; }, out: {inline: 1} } )
这里,就直接把结果输出的stdout 了,若是须要能够指定collection,将咱们的Map-Reduce结果存储下来。
来看一下结果
{ "results" : [ { "_id" : { "key0" : "BT", "key1" : "hardware", "key2" : "CRUD" }, "value" : 400 }, { "_id" : { "key0" : "BT", "key1" : "services", "key2" : "VOCI" }, "value" : 200 }, { "_id" : { "key0" : "IT", "key1" : "hardware", "key2" : "HIM" }, "value" : 200 }, { "_id" : { "key0" : "IT", "key1" : "software", "key2" : "Grad" }, "value" : 200 } ], "timeMillis" : 14, "counts" : { "input" : 5, "emit" : 5, "reduce" : 1, "output" : 4 }, "ok" : 1 }
这里能够看到,咱们的Sum 函数已经将emit 事后的 "productCategory" : "BT", "productSubCategory" : "hardware", "productName" : "CRUD"
这组数据的 salesAmt
累加了。
到这里,咱们基本就能够实现一个自定义的Function + Map-Reduce 的强大组合了!
上海小胖[MiracleYoung] 原创地址: https://segmentfault.com/u/shanghaixiaopang/articles
欢迎各位大神前来评论。
每周五,敬请期待,上海小胖[MiracleYoung] 独更。
若是夏雨荷还在大明湖畔等着个人话,我就不更了。