<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>schmichael&#039;s blog &#187; pymongo</title>
	<atom:link href="http://blog.schmichael.com/tag/pymongo/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.schmichael.com</link>
	<description>good good study, day day up</description>
	<lastBuildDate>Mon, 02 Aug 2010 17:28:53 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Making Server-Side MongoDB Functions Less Awkward</title>
		<link>http://blog.schmichael.com/2010/01/11/making-server-side-mongodb-functions-less-awkward/</link>
		<comments>http://blog.schmichael.com/2010/01/11/making-server-side-mongodb-functions-less-awkward/#comments</comments>
		<pubDate>Tue, 12 Jan 2010 00:54:19 +0000</pubDate>
		<dc:creator>Michael Schurter</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[pymongo]]></category>

		<guid isPermaLink="false">http://michael.susens-schurter.com/blog/?p=796</guid>
		<description><![CDATA[I&#8217;ve recently switched my project at work to use MongoDB for the user database and a few other datasets. Currently I don&#8217;t use many JavaScript functions, but when I do I like to store them on the server so that &#8230; <a href="http://blog.schmichael.com/2010/01/11/making-server-side-mongodb-functions-less-awkward/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently switched my project at work to use MongoDB for the user database and a few other datasets.</p>
<p>Currently I don&#8217;t use many JavaScript functions, but when I do I like to store them on the server so that they&#8217;re accessible when I&#8217;m poking around in a console.</p>
<p>I use something similar to the following function to load all of my JS functions onto the server when my app starts:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> pymongo
<span style="color: #ff7700;font-weight:bold;">import</span> pkg_resources
&nbsp;
<span style="color: #808080; font-style: italic;"># Relative to distribution's root</span>
SCRIPT_DIR = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'model'</span>, <span style="color: #483d8b;">'js'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> init_js<span style="color: black;">&#40;</span>db<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'Initializes server-side javascript functions'</span><span style="color: #483d8b;">''</span>
    scripts = <span style="color: #008000;">filter</span><span style="color: black;">&#40;</span>
            <span style="color: #ff7700;font-weight:bold;">lambda</span> f: f.<span style="color: black;">endswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'.js'</span><span style="color: black;">&#41;</span>,
            pkg_resources.<span style="color: black;">resource_listdir</span><span style="color: black;">&#40;</span>__name__, SCRIPT_DIR<span style="color: black;">&#41;</span>
        <span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> script <span style="color: #ff7700;font-weight:bold;">in</span> scripts:
        <span style="color: #808080; font-style: italic;"># Name the function after the script name</span>
        func_name, _ = script.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'.'</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
        script_path = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>SCRIPT_DIR, script<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Create a pymongo Code object</span>
        <span style="color: #808080; font-style: italic;"># otherwise it will be stored as a string</span>
        <span style="color: #dc143c;">code</span> = pymongo.<span style="color: #dc143c;">code</span>.<span style="color: black;">Code</span><span style="color: black;">&#40;</span>
                pkg_resources.<span style="color: black;">resource_string</span><span style="color: black;">&#40;</span>__name__, script_path<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Upsert the function</span>
        db.<span style="color: black;">system</span>.<span style="color: black;">js</span>.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span> <span style="color: #483d8b;">'_id'</span>: func_name, <span style="color: #483d8b;">'value'</span>: <span style="color: #dc143c;">code</span>, <span style="color: black;">&#125;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>However, using server-side functions from Python is awkward at best.  Say I have the JavaScript function:</p>
<p><strong>add.js</strong></p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>x<span style="color: #339933;">,</span> y<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000066; font-weight: bold;">return</span> x <span style="color: #339933;">+</span> y<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>To run that function via PyMongo requires wrapping the function call with placeholder parameters in a Code object and passing in values as a dict:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">var1 = <span style="color: #ff4500;">1</span>
var2 = <span style="color: #ff4500;">2</span>
result = db.<span style="color: #008000;">eval</span><span style="color: black;">&#40;</span>pymongo.<span style="color: #dc143c;">code</span>.<span style="color: black;">Code</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'add(a, b)'</span>, <span style="color: black;">&#123;</span><span style="color: #483d8b;">'a'</span>: var1, <span style="color: #483d8b;">'b'</span>: var2,<span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">assert</span> result == <span style="color: #ff4500;">3</span></pre></div></div>

<p><strong>Update:</strong> See <a href="http://michael.susens-schurter.com/blog/2010/01/11/making-server-side-mongodb-functions-less-awkward/comment-page-1/#comment-68027">MongoDB dev Mike Dirolf comment</a> to see a much more concise way of executing server-side functions.</p>
<p>Bearable for simple functions, but having to manually map parameters to values is tiresome and error prone with longer function signatures.</p>
<p>What I wanted was something more natural like:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">var1 = <span style="color: #ff4500;">1</span>
var2 = <span style="color: #ff4500;">2</span>
result = db.<span style="color: black;">add</span><span style="color: black;">&#40;</span>var1, var2<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">assert</span> result == <span style="color: #ff4500;">3</span></pre></div></div>

<p>I use a simple PyMongo Database object wrapper to make my life easier:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">string</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> pymongo.<span style="color: #dc143c;">code</span> <span style="color: #ff7700;font-weight:bold;">import</span> Code
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> ServerSideFunctions<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, db<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">db</span> = db
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> func_wrapper<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, func<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'Returns a closure for calling a server-side function.'</span><span style="color: #483d8b;">''</span>
        params = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span> <span style="color: #808080; font-style: italic;"># To keep params ordered</span>
        kwargs = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
        <span style="color: #ff7700;font-weight:bold;">def</span> server_side_func<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args<span style="color: black;">&#41;</span>:
            <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'Calls server side function with positional arguments.'</span><span style="color: #483d8b;">''</span>
            <span style="color: #808080; font-style: italic;"># Could be removed with better param generating logic</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>args<span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">string</span>.<span style="color: black;">letters</span><span style="color: black;">&#41;</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">TypeError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'%s() takes at most %d arguments (%d given)'</span>
                        <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>func, <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">string</span>.<span style="color: black;">letters</span><span style="color: black;">&#41;</span>, <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>args<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
            <span style="color: #808080; font-style: italic;"># Prepare arguments</span>
            <span style="color: #ff7700;font-weight:bold;">for</span> k, v <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">zip</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">string</span>.<span style="color: black;">letters</span>, args<span style="color: black;">&#41;</span>:
                kwargs<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span> = v
                params.<span style="color: black;">append</span><span style="color: black;">&#40;</span>k<span style="color: black;">&#41;</span> 
&nbsp;
            <span style="color: #808080; font-style: italic;"># Prepare code object</span>
            <span style="color: #dc143c;">code</span> = Code<span style="color: black;">&#40;</span><span style="color: #483d8b;">'%s(%s)'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>func, <span style="color: #483d8b;">', '</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>params<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>, kwargs<span style="color: black;">&#41;</span>
&nbsp;
            <span style="color: #808080; font-style: italic;"># Return result of server-side function</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">db</span>.<span style="color: #008000;">eval</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">code</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> server_side_func
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__getattr__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, func<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'Return a closure for calling server-side function named `func`'</span><span style="color: #483d8b;">''</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">func_wrapper</span><span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>
&nbsp;
dbjs = ServerSideFunctions<span style="color: black;">&#40;</span><span style="color: #483d8b;">'foo'</span><span style="color: black;">&#41;</span>
var1 = <span style="color: #ff4500;">1</span>
var2 = <span style="color: #ff4500;">2</span>
result = dbjs.<span style="color: black;">add</span><span style="color: black;">&#40;</span>var1, var2<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">assert</span> result == <span style="color: #ff4500;">3</span></pre></div></div>

<p>I&#8217;m tempted to monkey-patch PyMongo&#8217;s Database class to add a ServerSideFunctions instance directly as a js attribute, so then I could drop the confusing <code>dbjs</code> variable and just use:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">assert</span> db.<span style="color: black;">js</span>.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span> == <span style="color: #ff4500;">3</span></pre></div></div>

<p>If someone knows of a better way to access server-side MongoDB functions from Python, please let me know!</p>
<p><small>I modified this code to remove code specific to my project, so please let me know if there are errors.</small></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.schmichael.com/2010/01/11/making-server-side-mongodb-functions-less-awkward/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>
