Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Executing JS on MongoDB when inserting from PHP

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?


If you want even more details I'm trying to imitate autoincrement. This function that I'm writing should retrieve the last used value of incremental field, increment it and return the value thus assigning a unique value to the document that is being inserted.
like image 626
karka91 Avatar asked Mar 02 '26 11:03

karka91


1 Answers

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.

like image 109
jmikola Avatar answered Mar 05 '26 00:03

jmikola