From ab2d019349f22ead61b6612996ff90e066adf33f Mon Sep 17 00:00:00 2001 From: Harry Marr Date: Fri, 26 Feb 2010 13:23:15 +0000 Subject: [PATCH] Added server-side js docs --- docs/guide/querying.rst | 103 ++++++++++++++++++++++++++++++++++++++++ mongoengine/queryset.py | 11 ++++- 2 files changed, 112 insertions(+), 2 deletions(-) diff --git a/docs/guide/querying.rst b/docs/guide/querying.rst index 0742244d..d57b8b60 100644 --- a/docs/guide/querying.rst +++ b/docs/guide/querying.rst @@ -232,6 +232,109 @@ calling it with keyword arguments:: natively supported by MongoDB -- they are compiled to Javascript and sent to the server for execution. +Server-side javascript execution +================================ +Javascript functions may be written and sent to the server for execution. The +result of this is the return value of the Javascript function. This +functionality is accessed through the +:meth:`~mongoengine.queryset.QuerySet.exec_js` method on +:meth:`~mongoengine.queryset.QuerySet` objects. Pass in a string containing a +Javascript function as the first argument. + +The remaining positional arguments are names of fields that will be passed into +you Javascript function as its arguments. This allows functions to be written +that may be executed on any field in a collection (e.g. the +:meth:`~mongoengine.queryset.QuerySet.sum` method, which accepts the name of +the field to sum over as its argument). Note that field names passed in in this +manner are automatically translated to the names used on the database (set +using the :attr:`name` keyword argument to a field constructor). + +Keyword arguments to :meth:`~mongoengine.queryset.QuerySet.exec_js` are +combined into an object called :attr:`options`, which is available in the +Javascript function. This may be used for defining specific parameters for your +function. + +Some variables are made available in the scope of the Javascript function: + +* ``collection`` -- the name of the collection that corresponds to the + :class:`~mongoengine.Document` class that is being used; this should be + used to get the :class:`Collection` object from :attr:`db` in Javascript + code +* ``query`` -- the query that has been generated by the + :class:`~mongoengine.queryset.QuerySet` object; this may be passed into + the :meth:`find` method on a :class:`Collection` object in the Javascript + function +* ``options`` -- an object containing the keyword arguments passed into + :meth:`~mongoengine.queryset.QuerySet.exec_js` + +The following example demonstrates the intended usage of +:meth:`~mongoengine.queryset.QuerySet.exec_js` by defining a function that sums +over a field on a document (this functionality is already available throught +:meth:`~mongoengine.queryset.QuerySet.sum` but is shown here for sake of +example):: + + def sum_field(document, field_name, include_negatives=True): + code = """ + function(sumField) { + var total = 0.0; + db[collection].find(query).forEach(function(doc) { + var val = doc[sumField]; + if (val >= 0.0 || options.includeNegatives) { + total += val; + } + }); + return total; + } + """ + options = {'includeNegatives': include_negatives} + return document.objects.exec_js(code, field_name, **options) + +As fields in MongoEngine may use different names in the database (set using the +:attr:`name` keyword argument to a :class:`Field` constructor), a mechanism +exists for replacing MongoEngine field names with the database field names in +Javascript code. When accessing a field on a collection object, use +square-bracket notation, and prefix the MongoEngine field name with a tilde. +The field name that follows the tilde will be translated to the name used in +the database. Note that when referring to fields on embedded documents, +the name of the :class:`~mongoengine.EmbeddedDocumentField`, followed by a dot, +should be used before the name of the field on the embedded document. The +following example shows how the substitutions are made:: + + class Comment(EmbeddedDocument): + content = StringField(name='body') + + class BlogPost(Document): + title = StringField(name='doctitle') + comments = ListField(EmbeddedDocumentField(Comment), name='cs') + + # Returns a list of dictionaries. Each dictionary contains a value named + # "document", which corresponds to the "title" field on a BlogPost, and + # "comment", which corresponds to an individual comment. The substitutions + # made are shown in the comments. + BlogPost.objects.exec_js(""" + function() { + var comments = []; + db[collection].find(query).forEach(function(doc) { + // doc[~comments] -> doc["cs"] + var docComments = doc[~comments]; + + for (var i = 0; i < docComments.length; i++) { + // doc[~comments][i] -> doc["cs"][i] + var comment = doc[~comments][i]; + + comments.push({ + // doc[~title] -> doc["doctitle"] + 'document': doc[~title], + + // comment[~comments.content] -> comment["body"] + 'comment': comment[~comments.content] + }); + } + }); + return comments; + } + """) + .. _guide-atomic-updates: Atomic updates diff --git a/mongoengine/queryset.py b/mongoengine/queryset.py index 3ac8a37a..9592236d 100644 --- a/mongoengine/queryset.py +++ b/mongoengine/queryset.py @@ -373,7 +373,7 @@ class QuerySet(object): def in_bulk(self, object_ids): """Retrieve a set of documents by their ids. - :param object_ids: a list or tuple of ``ObjectId``s + :param object_ids: a list or tuple of ``ObjectId``\ s :rtype: dict of ObjectIds as keys and collection-specific Document subclasses as values. """ @@ -455,7 +455,7 @@ class QuerySet(object): post = BlogPost.objects(...).only("title") - :param *fields: fields to include + :param fields: fields to include """ self._loaded_fields = list(fields) return self @@ -618,6 +618,13 @@ class QuerySet(object): current query; and ``options``, which is an object containing any options specified as keyword arguments. + As fields in MongoEngine may use different names in the database (set + using the :attr:`name` keyword argument to a :class:`Field` + constructor), a mechanism exists for replacing MongoEngine field names + with the database field names in Javascript code. When accessing a + field, use square-bracket notation, and prefix the MongoEngine field + name with a tilde (~). + :param code: a string of Javascript code to execute :param fields: fields that you will be using in your function, which will be passed in to your function as arguments