Executing JS On MongoDB When Inserting From PHP
Solution 1:
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.
Solution 2:
You can't do what you want with MongoDB, exactly. When you run your example in the shell, it calls the db.eval...
bit first, then passes the computed result as part of the document. The only thing Mongo will evaluate during a write operation are the special modifier fields as part of an update (or upsert, if you want). None of those will let you do a per-collection counter, though.
For autoincrement, you'll need to do two queries. You can use findAndModify
to atomically increment and retrieve a number, then assign it to your lines
value.
Here's how you'd do it from the shell:
counter = db.counters.findAndModify({
query: {_id: "line-counter"},
update: {$inc: {value: 1}},
new: true,
upsert: true}).value
db.sandbox.insert({line: counter})
Solution 3:
Since you are trying to do an incermenting field please let me say that you are doing it wrong.
Server-side evaulation has serious problems as @jmikola states including the fact that it is near on incompatible with everything including sharding. In fact I recommend not even learning about server side execution so much that I will not even show you an example of how to do it.
I would recommend you move away from server-side execution of JS, it is not like stored procedures or triggers in SQL and really does not run the same. The JS console is just another driver much like the MySQL console and I think this is where you are getting the confusion, you some how think that the console is like server-side execution (stored procedures etc) but it is not, it is just another client.
A Map Reduce is the only real "server-side" execution that is truely supported. You can of course store scripts within system.js for future use but this is more designed to store cumbersome MR scripts within the DB so your not constantly having to write them out or send huge files over the network repeatedly.
This function that I'm writing should retrieve the last used value of incremental field
This function most definitely would not work the same way as you expect since concurrency would make that new ID invalid because it may have already been used by another insert. Of course this depends upon the frequency of inserts but even under a slight load your IDs will not increment correctly.
To achieve an auto-incrementing ID you can actually use findandmodify as shown here: http://www.mongodb.org/display/DOCS/How+to+Make+an+Auto+Incrementing+Field and within @MrKurts answer.
Post a Comment for "Executing JS On MongoDB When Inserting From PHP"