Skip to content

DOCS-673 migrate server side code execution page #492

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 20, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions source/applications.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The following documents outline basic application development topics:
applications/drivers
applications/optimization
applications/database-references
applications/server-side-code-execution
applications/gridfs
core/object-id
core/capped-collections
Expand Down
150 changes: 150 additions & 0 deletions source/applications/server-side-code-execution.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
==========================
Server-side Code Execution
==========================

.. default-domain:: mongodb

MongoDB supports server-side execution of JavaScript code using various
methods.

.. note:: The JavaScript code execution takes a JavaScript lock.

.. _server-side-map-reduce:

Map-Reduce
----------

MongoDB performs the execution of JavaScript functions for
:doc:`/applications/map-reduce` operations on the server. Within these
JavaScript functions, you must not access the database for any reason,
including to perform reads.

See the :method:`db.collection.mapReduce()` and the
:doc:`/applications/map-reduce` documentation for more information,
including examples of map-reduce. See :ref:`map-reduce concurrency
<map-reduce-concurrency>` section for concurrency information for
map-reduce.

.. _server-side-eval:

``eval`` Command
----------------

The :dbcommand:`eval` command, and the corresponding :program:`mongo`
shell method :method:`db.eval()`, evaluates JavaScript functions on the
database server. This command may be useful if you need to touch a lot
of data lightly since the network transfer of the data could become a
bottleneck if performing these operations on the client-side.

.. warning::

By default, :dbcommand:`eval` command requires a write lock. As such
:dbcommand:`eval` will block all other read and write operations
while it runs.

See :dbcommand:`eval` command and :method:`db.eval()` documentation for
more information, including examples.

Running .js files via a mongo shell instance on the server
----------------------------------------------------------

Running a JavaScript (.js) file using a :program:`mongo` shell instance
on the server is a good technique for performing batch administrative
work. When you run :program:`mongo` shell on the server, connecting via
the localhost interface, the connection is fast with low latency.
Additionally, this technique has the advantage over the
:dbcommand:`eval` command since the command :dbcommand:`eval` blocks
all other operations.

.. _server-side-where:

$where Operator
---------------

To perform :doc:`/core/read-operations`, in addition to the standard
operators (e.g. :operator:`$gt`, :operator:`$lt`), with the
:operator:`$where` operator, you can also express the query condition
either as a string or a full JavaScript function that specifies a
SQL-like ``WHERE`` clause. However, use the standard operators whenever
possible since :operator:`$where` operations have significantly slower
performance.

.. warning::

Do not write to the database within the :operator:`$where`
JavaScript function.

See :operator:`$where` documentation for more information, including
examples.

Storing Functions Server-side
-----------------------------

.. note::

We do **not** recommend using server-side stored functions if
possible.

There is a special system collection named ``system.js`` that can store
JavaScript functions for reuse.

To store a function, you can use the :method:`db.collection.save()`, as
in the following example:

.. code-block:: javascript

db.system.js.save(
{
_id : "myAddFunction" ,
value : function (x, y){ return x + y; }
}
);

- The ``_id`` field holds the name of the function and is unique per
database.

- The ``value`` field holds the function definition

Once you save a function in the ``system.js`` collection, you can use
the function from any JavaScript context (e.g. :ref:`eval
<server-side-eval>`, :ref:`$where <server-side-where>`,
:ref:`map-reduce <server-side-map-reduce>`).

Consider the following example from the :program:`mongo` shell that
first saves a function named ``echoFunction`` to the ``system.js``
collection and calls the function using :ref:`db.eval()
<server-side-eval>`:

.. code-block:: javascript

db.system.js.save(
{ _id: "echoFunction",
value : function(x) { return x; }
}
)

db.eval( "echoFunction( 'test' )" )

See `<http://github.com/mongodb/mongo/tree/master/jstests/storefunc.js>`_ for a full example.

.. versionadded:: 2.1
In the :program:`mongo` shell, you can use
:method:`db.loadServerScripts()` to load all the scripts saved in
the ``system.js`` collection for the current db. Once loaded, you
can invoke the functions directly in the shell, as in the following
example:

.. code-block:: javascript

db.loadServerScripts();

echoFunction(3);

myAddFunction(3, 5);

Concurrency
-----------

Refer to the individual method or operator documentation for any
concurrency information. See also the :ref:`concurrency table
<faq-concurrency-operations-locks>`.
2 changes: 2 additions & 0 deletions source/faq/concurrency.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ opportunity to complete.
is available in memory, the read will reacquire the lock to
completes the operation.

.. _faq-concurrency-operations-locks:

Which operations lock the database?
-----------------------------------

Expand Down
167 changes: 136 additions & 31 deletions source/reference/command/eval.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,163 @@
eval
====

.. Edits to this page should be carried over to the method db.eval.txt
file.

.. default-domain:: mongodb

.. dbcommand:: eval

The :dbcommand:`eval` command evaluates JavaScript functions
on the database server. Consider the following (trivial) example:
The :dbcommand:`eval` command evaluates JavaScript functions on the
database server and has the following form:

.. code-block:: none

{
eval: <function>,
args: [ <arg1>, <arg2> ... ],
nolock: <boolean>
}

The command contains the following fields:

:field JavaScript function:
A JavaScript function to evaluate. The function may
accept no arguments, as in the following example:

.. code-block:: javascript

function () {

...

}

The function can also accept arguments, as in the following example:

.. code-block:: javascript

function (arg1, arg2) {

...
}

If you specify arguments, you must include the corresponding
``args`` field in the command.

:field Array args:
An array of corresponding arguments to the ``function``. Omit
``args`` if the ``function`` does not take arguments.

:field Boolean nolock:
Optional. Specifies whether to disable the write lock. By
default, :dbcommand:`eval` takes a write lock. There are
circumstances where the :dbcommand:`eval` executes a strictly
read-only operation that does not need to block other
operations. If ``nolock`` is ``true``, the
:dbcommand:`eval` does not take a write lock.

.. warning::

Do not disable the write lock if the function may modify
the contents of the database in any way.

Consider the following example which uses :dbcommand:`eval` to
perform an increment and calculate the average on the server:

.. code-block:: javascript

{ eval: function() { return 3+3 } }
db.runCommand( {
eval: function(name, incAmount) {
var doc = db.myCollection.findOne( { name : name } );

doc = doc || { name : name , num : 0 , total : 0 , avg : 0 };

doc.num++;
doc.total += incAmount;
doc.avg = doc.total / doc.num;

db.myCollection.save( doc );
return doc;
},
args: [ "eliot", 5 ]
}
);

The shell also provides a helper method, so you can express the
above as follows:
The ``db`` in the function refers to the current database.

The shell also provides a helper method :method:`db.eval()`, so you
can express the above as follows:

.. code-block:: javascript

db.eval( function() { return 3+3 } );
db.eval( function(name, incAmount) {
var doc = db.myCollection.findOne( { name : name } );

doc = doc || { name : name , num : 0 , total : 0 , avg : 0 };

The shell's JavaScript interpreter evaluates functions entered
directly into the shell. If you want to use the server's
interpreter, you must run :dbcommand:`eval`.
doc.num++;
doc.total += incAmount;
doc.avg = doc.total / doc.num;

db.myCollection.save( doc );
return doc;
},
"eliot", 5 );

Be aware of following behaviors and limitations:
You cannot pass the ``nolock`` flag to the :method:`db.eval()`
in the :program:`mongo` shell.

- :dbcommand:`eval` does not work in :term:`sharded <sharding>`
environments.
If you want to use the server's interpreter, you must run
:dbcommand:`eval`. Otherwise, the :program:`mongo` shell's
JavaScript interpreter evaluates functions entered directly into the
shell.

- The ``eval`` operation take a write lock by default. This means
that writes to database aren't permitted while it's running. You
can, however, disable the lock by setting the ``nolock`` flag to
``true``. For example:
If an error occurs, :dbcommand:`eval` throws an exception. Consider
the following invalid function that uses the variable ``x`` without
declaring it as an argument:

.. code-block:: javascript

.. code-block:: javascript
db.runCommand(
{
eval: function() { return x + x; },
args: [3]
}
)

The statement will result in the following exception:

.. code-block:: javascript

{ eval: function() { return 3+3 }, nolock: true }
{
"errno" : -3,
"errmsg" : "invoke failed: JS Error: ReferenceError: x is not defined nofile_b:1",
"ok" : 0
}

Using :method:`db.runCommand()` helper, in the :program:`mongo`
shell, this command would resemble:
.. warning::

.. code-block:: javascript
- The :dbcommand:`eval` operation takes a write lock by default.
This means that other read and write operations to the database
are blocked while :dbcommand:`eval` is running. You can,
however, disable the lock by setting the ``nolock`` flag to
``true`` if the ``eval`` performs a strictly read-only
operation.

db.runCommand( { eval: function() { return 3+3 }, nolock: true } )
- :dbcommand:`eval` also takes a JavaScript lock.

.. warning::
- Do not use :dbcommand:`eval` for long running operations as
:dbcommand:`eval` blocks all other operations. Consider using
:doc:`other server side code execution options
</applications/server-side-code-execution>`.

Do not disable the write lock if the operation may modify the
contents of the database in anyway.
- You can not use :dbcommand:`eval` with :term:`sharded
<sharding>` data. In general, you should avoid using
:dbcommand:`eval` in :term:`sharded cluster`; nevertheless, it
is possible to use :dbcommand:`eval` with non-sharded
collections and databases stored in a :term:`sharded cluster`.

You cannot pass the ``nolock`` option to :method:`db.eval()` in
the :program:`mongo` shell.
.. seealso::

There are some circumstances where the :method:`db.eval()`
implements a strictly-read only operation that need not block
other operations when disabling the write lock may be useful. Use
this functionality with extreme caution.
:doc:`/applications/server-side-code-execution`
Loading