在Aggregation管道,MapReduce或runCommand中使用存储的JavaScript函数

Pra*_*apa 4 mongodb mongodb-query aggregation-framework

有没有办法使用db.system.js.save(...)在管道或mapreduce中保存的用户定义函数?

Bla*_*ven 13

您保存的任何函数system.js都可以由"JavaScript"处理语句(如$where运算符)使用,mapReduce并且可以通过_id值被引用来引用.

db.system.js.save({ 
   "_id": "squareThis", 
   "value": function(a) { return a*a } 
})
Run Code Online (Sandbox Code Playgroud)

并将一些数据插入"sample"集合:

{ "_id" : ObjectId("55aafd2bacbed38e06f9eccf"), "a" : 1 }
{ "_id" : ObjectId("55aafea6acbed38e06f9ecd0"), "a" : 2 }
{ "_id" : ObjectId("55aafeabacbed38e06f9ecd1"), "a" : 3 }
Run Code Online (Sandbox Code Playgroud)

然后:

db.sample.mapReduce(
    function() {
       emit(null, squareThis(this.a));
    },
    function(key,values) {
        return Array.sum(values);
    },
    { "out": { "inline": 1 } }
 );
Run Code Online (Sandbox Code Playgroud)

得到:

   "results" : [
            {
                    "_id" : null,
                    "value" : 14
            }
    ],
Run Code Online (Sandbox Code Playgroud)

或者$where:

db.sample.find(function() { return squareThis(this.a) == 9 })
{ "_id" : ObjectId("55aafeabacbed38e06f9ecd1"), "a" : 3 }
Run Code Online (Sandbox Code Playgroud)

但是在"两种情况"中你都可以使用全局变量,例如数据库db引用或其他函数.两者$wheremapReduce文档都包含您在此处可以执行的限制的信息.因此,如果您认为您将要执行"在另一个集合中查找数据"之类的操作,那么您可以忘记它,因为它是"不允许".

无论如何,每个 MongoDB命令操作实际上都是"引擎盖"下的"runCommand"操作.但除非该命令实际上正在做的是"调用JavaScript处理引擎",否则使用变得无关紧要.无论如何,只有少数命令执行此操作,是mapReduce,group或者eval,当然还有查找操作$where.


聚合框架根本以任何方式使用JavaScript.你可能会误会,正如其他人做过这样的声明,这不符合你的想法:

db.sample.aggregate([
    { "$match": {
        "a": { "$in": db.sample.distinct("a") }
    }}
])
Run Code Online (Sandbox Code Playgroud)

因此,聚合管道"不在内部运行",而是.distinct()在将管道发送到服务器之前"评估" 该调用的"结果" .就像外部变量一样,无论如何:

var items = [1,2,3];
db.sample.aggregate([
    { "$match": {
        "a": { "$in": items }
    }}
])
Run Code Online (Sandbox Code Playgroud)

两者都以相同的方式发送到服务器:

db.sample.aggregate([
    { "$match": {
        "a": { "$in": [1,2,3] }
    }}
])
Run Code Online (Sandbox Code Playgroud)

因此,"不可能"在聚合管道中"调用"任何JavaScript函数,也没有任何一点是"传入"结果通常来自保存的内容system.js."代码"需要"加载到客户端",只有JavaScript引擎才能实际执行任何操作.

使用聚合框架,所有可用的"运算符"实际上是本机编码的函数,而不是提供的"自由格式"JavaScript解释mapReduce.因此,不使用"JavaScript",而是使用运算符本身:

db.sample.aggregate([
    { "$group": {
        "_id": null,
        "sqared": { "$sum": {
           "$multiply": [ "$a", "$a" ]
        }}
    }}
])

{ "_id" : null, "sqared" : 14 }
Run Code Online (Sandbox Code Playgroud)

因此,对于使用system.js中保存的函数可以执行的操作存在限制,并且您可能要做的是:

  • 不允许,例如从其他集合访问数据
  • 不是真的需要,因为逻辑通常是自包含的
  • 或者可能更好地以客户端逻辑或其他不同的形式实现

我能真正想到的唯一实际用途是你有许多"mapReduce"操作,这些操作无法以任何其他方式完成,你有各种"共享"功能,你宁愿只存储在服务器上而不是维护mapReduce函数调用.

但是再一次,mapReduce相对于聚合框架的90%原因通常是集合的"文档结构"选择不当,并且"需要"JavaScript功能来遍历文档以进行搜索和分析.

因此,您可以在允许的约束下使用它,但在大多数情况下,您可能根本不应该使用它,而是修复导致您首先认为您需要此功能的其他问题.