调用 db.system.js $where 中的函数


Calling db.system.js Function in $where

作为一个基本的例子,我保存了这个函数:

db.system.js.save({_id: "sum", value: function (x, y) { return x + y; }});

但是当我尝试调用$where时,我得到一个不存在的引用。

<?php
$collection = $link -> selectCollection('foo' ,'bar');
$collection -> find(array(
'$where' =>'sum(this.x, this.y)'
));
?>

和错误

ReferenceError: sum is not defined :

我应该保存它还是以其他方式访问它?

您是否连接到

使用 shell 连接到的 PHP 代码中的同一数据库命名空间?我认为不是!

无论如何,您误解了此上下文中$where的概念,因为除了集合中已包含的数据之外,您只能计算而不能返回修改后的结果。

唯一可以实际返回与现有文档不同的内容是 .mapReduce().aggregate() .

因此,为了演示,如果您定义集合,则在"同一命名空间"中:

db.djunk.insert({ "x": 1, "y": 2 })

然后运行.mapReduce()

db.dbjunk.mapReduce(
    function() {
        emit(this._id, sum(this.x,this.y))
    },
    function() {}, // does nothing here where already unique
    { "out": { "inline": 1 } }
)

这将返回实际求和结果:

{
    "_id" : ObjectId("571a9bb951d042a7a896fd92"),
    "value" : 3
}

$where所能做的就是"逻辑地"选择文档:

db.djunk.find(function() {
    return sum(this.x,this.y) > 3
})

这不符合条件。

但是当然,你真的不需要这样做,并且通常应该尽可能避免任何JavaScript的服务器执行。它比本机运算符慢得多,您可以使用本机运算符执行很多操作。

因此,与其.mapReduce()调用.aggregate()

db.djunk.aggregate([
    { "$project": {
        "total": { "$add": [ "$x", "$y" ] }
    }}
])

而不是JavaScript评估,再次调用.aggregate()$redact进行"逻辑"过滤:

db.djunk.aggregate([
    { "$redact": {
        "$cond": {
            "if": { "$gt": [ { "$add": [ "$x", "$y" ] }, 3 ] },
            "then": "$$KEEP",
            "else": "$$PRUNE"
        }      
    }}
])

因此,在大多数情况下,总有更好的替代方法来使用JavaScript评估。当然,在实际需要 JavaScript 评估的情况下,实际上很少有情况真正需要服务器存储函数。

但是您在此处的基本错误是因为该函数位于不同的命名空间中,或者实际上您在两者之间重新启动了服务器。但总的来说,你可能不应该使用存储函数。