您似乎认为可以在聚合管道中调用 JavaScript 函数,但您不能这样做。您误认为在管道中执行的函数结果中的变量实际上是“插值”。
例如,如果我这样做:
var getNumbers = function() { return [ 1,2,3 ] };
然后我称之为:
db.collection.aggregate([
{ "$project": {
"mynums": getNumbers()
}}
])
然后在 JavaScript shell 中实际发生的情况是值被“插值”和“在”指令发送到服务器之前,如下所示:
db.collection.aggregate([
{ "$project": {
"mynums": [1,2,3]
}}
])
为了进一步证明,在服务器上“仅”存储一个函数:
db.system.js.save({ "_id": "hello", "value": function() { return "hello" } })
然后尝试运行聚合语句:
db.collection.aggregate([
{ "$project": {
"greeting": hello()
}}
])
这将导致异常:
E QUERY [main] ReferenceError: hello is not defined at (shell):1:69
这是因为执行发生在“客户端”而不是“服务器”上,并且该函数在客户端上不存在。
聚合框架不能运行 JavaScript,因为它没有这样做的规定。所有操作都在本机代码中执行,没有调用 JavaScript 引擎。因此,您可以使用那里的运算符:
db.collection.aggregate([
{ "$project": {
"total": { "$add": [ 1, 2 ] },
"field_total": { "$subtract": [ "$gross", "$tax" ] }
}}
])
如果您无法使用运算符来获得结果,那么您可以运行 JavaScript 代码的唯一方法是运行 mapReduce,这当然使用 JavaScript 引擎与集合中的数据进行交互。如果需要,您还可以从那里引用逻辑中的服务器端函数:
{ "key": 1, "value": 1 },
{ "key": 1, "value": 2 },
{ "key": 1, "value": 3 }
db.system.js.save({ "_id": "square", "value": function(num) { return num * num } })
db.collection.mapReduce(
function() {
emit(this.key,square(this.value))
},
function(key,values) {
return Array.sum(values);
},
{ "out": { "inline": 1 } }
)
返回:
{
"_id": 1,
"value": 14
}
所以这不是关于“如何传递字段值”,而是关于聚合框架不以任何方式支持 JavaScript 的事实,并且您认为发生的事情实际上并非如此。