When using mongo shell I can run something like this:
db.sandbox.insert({"line" : db.eval('storedFunction()') })
or
db.sandbox.insert({"line" : function() {return 1337} })
I was unable to achieve the same effect using php. What I wish to do is run something similar to
$fnc = "function() {return 123}";
$col = (new Mongo)->database->collection;
$col->insert(['col' => new MongoCode($fnc)]);
and find
{
"_id" : ....,
"col" : 123
}
in the collection. How can I achieve this? Is it even possible?
JavaScript functions are a first-class type in BSON (see specification), so in both examples (JS shell and PHP) you will be storing the function itself in the field. If you want to evaluate the function, you would have to execute server-side JavaScript. Consider this example:
<?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']);
It yields the following output:
object(MongoCode)#7 (2) {
["code"]=>
string(26) "function() { return 123; }"
["scope"]=>
array(0) {
}
}
float(123)
If your function depends on some external state (e.g. it needs to run a query to compute its result), you'd probably want to store it in a separate field and periodically iterate over your documents and update another field to hold its output. As you implement this, keep in mind that server-side code evaluation has several concurrency limitations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With