3

使用 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
} 

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


如果您想要更多详细信息,我正在尝试模仿自动增量。我正在编写的这个函数应该检索增量字段的最后使用值,将其递增并返回该值,从而为正在插入的文档分配一个唯一值。

4

3 回答 3

3

JavaScript 函数是 BSON 中的一等类型(参见规范),因此在两个示例(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)

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

于 2012-08-03T14:59:55.173 回答
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})
于 2012-08-07T20:25:15.010 回答
1

既然你正在尝试做一个增量领域,请让我说你做错了。

正如@jmikola 所说,服务器端评估存在严重问题,包括它几乎与包括分片在内的所有内容不兼容。事实上,我什至建议不要过多地学习服务器端执行,以至于我什至不会向您展示如何做到这一点的示例。

我建议你远离 JS 的服务器端执行,它不像 SQL 中的存储过程或触发器,而且运行起来也不一样。JS 控制台只是另一个驱动程序,很像 MySQL 控制台,我认为这就是您感到困惑的地方,您有些人认为控制台就像服务器端执行(存储过程等),但事实并非如此,它只是另一个客户。

Map Reduce 是唯一真正受支持的真正“服务器端”执行。您当然可以将脚本存储在 system.js 中以备将来使用,但这更多是为了将繁琐的 MR 脚本存储在数据库中,这样您就不必经常将它们写出或通过网络反复发送大文件。

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

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

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

于 2012-08-13T13:13:53.610 回答