在聚合管道、MapReduce 或 runCommand 中使用存储的 JavaScript 函数

Using stored JavaScript functions in the Aggregation pipeline, MapReduce or runCommand

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

您保存到 system.js 的任何函数都可供 "JavaScript" 处理语句使用,例如 $where operator and mapReduce 并且可以被分配的 _id 值引用.

db.system.js.save({ 
   "_id": "squareThis", 
   "value": function(a) { return a*a } 
})

并且一些数据插入到 "sample" 集合中:

{ "_id" : ObjectId("55aafd2bacbed38e06f9eccf"), "a" : 1 }
{ "_id" : ObjectId("55aafea6acbed38e06f9ecd0"), "a" : 2 }
{ "_id" : ObjectId("55aafeabacbed38e06f9ecd1"), "a" : 3 }

然后:

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

给出:

   "results" : [
            {
                    "_id" : null,
                    "value" : 14
            }
    ],

$where:

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

但在 "neither" 情况下,您可以使用全局变量,例如数据库 db 引用或其他函数。 $wheremapReduce 文档都包含您可以在此处执行的操作的限制信息。所以如果你认为你会做类似 "look up data in another collection" 的事情,那么你可以忘记它,因为它是 "Not Allowed".

每个 MongoDB命令操作实际上是调用"runCommand"操作"under the hood"反正。但是除非该命令实际执行的操作是 "calling a JavaScript processing engine" 否则用法就变得无关紧要了。无论如何只有少数命令可以执行此操作,如 mapReducegroupeval,当然还有 $where.

的查找操作

聚合框架以任何方式使用JavaScript。您可能会误会,就像其他人所做的这样的声明一样,它并没有按照您的想法行事:

db.sample.aggregate([
    { "$match": {
        "a": { "$in": db.sample.distinct("a") }
    }}
])

所以那是 "not running inside" 聚合管道,而是那个 .distinct() 调用的 "result" 是 "evaluated" 之前管道被发送到服务器。就像外部变量一样完成:

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

两者基本上以相同的方式发送到服务器:

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

所以它是 "not possible" 到 "call" 聚合管道中的任何 JavaScript 函数,也没有任何意义是 "passing in" 通常来自保存在system.js。 "code" 需要是 "loaded to the client" 并且只有 JavaScript 引擎才能真正用它做任何事情。

使用聚合框架,所有可用的 "operators" 实际上都是本机编码函数,而不是为 mapReduce 提供的 "free form" JavaScript 解释。所以不用写 "JavaScript",而是使用运算符本身:

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

{ "_id" : null, "sqared" : 14 }

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

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

我真正能想到的唯一实际用途是,您有许多 "mapReduce" 操作无法通过任何其他方式完成,并且您有各种 "shared" 功能,您更愿意只存储在服务器上而不是在每个 mapReduce 函数调用中维护。

但话又说回来,mapReduce 优于聚合框架的 90% 原因通常是 "document structure" 集合选择不当,JavaScript 功能是 "required"遍历文档进行搜索分析。

因此您可以在允许的限制下使用它,但在大多数情况下您可能根本不应该使用它,而是解决其他让您认为您首先需要此功能的问题。