从PHP插入时在MongoDB上执行JS

时间:2012-08-03 13:18:35

标签: php javascript json mongodb

使用mongo shell时我可以运行这样的东西:

db.sandbox.insert({"line" : db.eval('storedFunction()') })
       or
db.sandbox.insert({"line" : function() {return 1337} })

我无法使用php实现相同的效果。 我想做的是运行类似的东西

$fnc = "function() {return 123}";
$col = (new Mongo)->database->collection;
$col->insert(['col' => new MongoCode($fnc)]);

并找到

{
   "_id" : ...., 
   "col" : 123
} 

在集合中。我怎样才能做到这一点?它甚至可能吗?

<小时/> 如果你想要更多的细节我试图模仿自动增量。我正在编写的这个函数应该检索最后使用的增量字段值,增加它并返回值,从而为正在插入的文档分配一个唯一值。

3 个答案:

答案 0 :(得分:3)

JavaScript函数是BSON中的第一类类型(请参阅specification),因此在两个示例(JS shell和PHP)中,您将在字段中存储函数本身。如果要评估该函数,则必须执行服务器端JavaScript。考虑这个例子:

<?php

$m = new Mongo();
$db = $m->test;
$c = $db->foo;
$c->drop();

$f = 'function() { return 123; }';

$c->insert(['f' => new MongoCode($f)]);
var_dump($c->findOne()['f']);

$g = <<<'END'
    function() {
        var doc = db.foo.findOne();
        db.foo.update(
            { _id: doc._id },
            { $set: { f: doc.f() }}
        );
    }
END;

$db->execute(new MongoCode($g));

$c->insert(['f' => new MongoCode($f)]);
var_dump($c->findOne()['f']);

它产生以下输出:

object(MongoCode)#7 (2) {
  ["code"]=>
  string(26) "function() { return 123; }"
  ["scope"]=>
  array(0) {
  }
}
float(123)

如果您的函数依赖于某些外部状态(例如,它需要运行查询来计算其结果),您可能希望将其存储在单独的字段中并定期迭代您的文档并更新另一个字段以保存其输出。在实现此功能时,请记住server-side code evaluation有几个并发限制。

答案 1 :(得分:1)

你完全不能用MongoDB做你想做的事。在shell中运行示例时,它首先调用db.eval...位,然后将计算结果作为文档的一部分传递。 Mongo在写操作期间唯一要评估的是特殊修饰符字段作为更新的一部分(如果需要,则为upsert)。但是,这些都不会让你做一个收集计数器。

对于自动增量,您需要进行两次查询。您可以使用findAndModify以原子方式递增并检索数字,然后将其分配给lines值。

以下是你如何从shell中做到这一点:

counter = db.counters.findAndModify({
  query: {_id: "line-counter"}, 
  update: {$inc: {value: 1}}, 
  new: true, 
  upsert: true}).value
db.sandbox.insert({line: counter})

答案 2 :(得分:1)

既然你正在尝试进行一个追踪领域,请告诉我你做错了。

服务器端的评估存在严重的问题,因为@jmikola声称它几乎与包括分片在内的所有内容不兼容。事实上,我建议甚至不要了解服务器端执行,以至于我甚至不会向您展示如何执行此操作的示例。

我建议你远离JS的服务器端执行,它不像SQL中的存储过程或触发器,并且实际上不会运行相同的。 JS控制台只是另一个驱动程序,就像MySQL控制台一样,我认为这是你得到混乱的地方,你有些人认为控制台就像服务器端执行(存储过程等)但它不是,它只是另一个客户。

Map Reduce是真正支持的唯一真正的“服务器端”执行。您当然可以在system.js中存储脚本以供将来使用,但这更适用于在DB中存储繁琐的MR脚本,因此您不必经常将其写出或通过网络重复发送大量文件。

  

我正在编写的这个函数应该检索最后使用的增量字段值

这个函数绝对不会像你期望的那样工作,因为并发会使新ID无效,因为它可能已经被另一个插入使用了。当然这取决于插入的频率,但即使在轻微负载下,您的ID也不会正确增加。

要实现自动递增ID,您实际上可以使用findandmodify,如下所示:http://www.mongodb.org/display/DOCS/How+to+Make+an+Auto+Incrementing+Field和@MrKurts回答。