<?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; mongodb</title>
	<atom:link href="http://blog.schmichael.com/tag/mongodb/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.schmichael.com</link>
	<description>good good study, day day up</description>
	<lastBuildDate>Sat, 05 Nov 2011 23:13:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Failing with MongoDB</title>
		<link>http://blog.schmichael.com/2011/11/05/failing-with-mongodb/</link>
		<comments>http://blog.schmichael.com/2011/11/05/failing-with-mongodb/#comments</comments>
		<pubDate>Sat, 05 Nov 2011 19:06:03 +0000</pubDate>
		<dc:creator>Michael Schurter</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[mongodb]]></category>

		<guid isPermaLink="false">http://blog.schmichael.com/?p=979</guid>
		<description><![CDATA[Update: Sorry this isn&#8217;t my best piece of writing and there seems to be some confusion. The dataset in question was first in a 1.8 master/slave pair and then migrated to sharded replica sets and 2.0.0. For a bit of &#8230; <a href="http://blog.schmichael.com/2011/11/05/failing-with-mongodb/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><b>Update:</b> Sorry this isn&#8217;t my best piece of writing and there seems to be some confusion. The dataset in question was first in a 1.8 master/slave pair and then migrated to sharded replica sets and 2.0.0.</p>
<p>For a bit of history of my dealings with MongoDB at Urban Airship, I gave a couple versions of a Scaling with MongoDB talk:</p>
<ul>
<li>
<a href="http://opensourcebridge.org/2011/wiki/Scaling_with_MongoDB">at Open Source Bridge (latest &#038; greatest)</a>
</li>
<li><a href="http://blog.schmichael.com/2011/02/02/schmongodb-slides-from-update-portland/">at Update Portland (original, less polished version)</a></li>
</ul>
<p>My coworker Adam Lowry even gave a follow-up talk of sorts at <a href="http://postgresopen.org/2011/schedule/presentations/98/">Postgres Open 2011</a> (<a href="http://wiki.postgresql.org/images/7/7f/Adam-lowry-postgresopen2011.pdf">slides</a>) about migrating one of our datasets off of MongoDB and (back) on to PostgreSQL.</p>
<p>After reading through those slides you&#8217;re probably wondering why we&#8217;re still dealing with MongoDB at all. We fully intended to migrate our data out of it by now, but priorities change, deadlines slip, and we never expected one of our last uses of MongoDB to experience a surge in growth.</p>
<p>The dataset in question seemed ideal for MongoDB:</p>
<ul>
<li>Ephemeral &#8211; if we lose it we experience service degradation for a short while, but nothing catastrophic</li>
<li>Small &#8211; easily fits into memory (~15 GB)</li>
<li>Secondary index &#8211; In a key/value store we would have had to manage a secondary index manually</li>
</ul>
<p>So this dataset dodged a lot of the previous problems we had with MongoDB and seemed safe to migrate at our leisure.</p>
<p><a name="global_write_lock"><b>Global Write Lock</b></a></p>
<p><a href="http://www.mongodb.org/display/DOCS/How+does+concurrency+work#Howdoesconcurrencywork-Read%2FWriteLock">MongoDB has a global write lock.</a> This means that while applying an insert or update, a single mongod instance can&#8217;t respond to other queries.</p>
<p>Our dataset may be small but it has a heavy read and write load. When the service it backed experienced a surge in usage, MongoDB quickly became CPU bound. This was especially frustrating considering mongod was running in a simple master/slave setup on two servers: each with 16 cores and enough memory to hold all the data a few times over again.</p>
<p>Because of the global write lock and heavy write load, operations are effectively serialized and executed on a single core. Meaning our servers didn&#8217;t even look loaded, as just 1 core would be 100% utilized by mongod.</p>
<p><a name="sharding"><b>Let the Sharding Begin</b></a></p>
<p>So we need to utilize multiple cores&#8230;<br />
To do that we need multiple write locks&#8230;<br />
There&#8217;s 1 write lock per mongod. So&#8230;<br />
&#8230;multiple mongods per server?</p>
<p>We&#8217;d been avoiding sharding after having no luck getting it working in the 1.5.x dev series, but it&#8217;s our only choice now to get multiple mongods. I ran some tests and it seemed like we could turn our master/slave setup into a 2 shard setup with 2 mongods and 1 arbiter per shard with downtime in the seconds or low minutes.</p>
<p>The operational complexity of configuring a MongoDB cluster is daunting with each component bringing its own caveats:</p>
<p><b>mongod config servers</b></p>
<ul>
<li>You need <i>exactly</i> 3 config mongods (1 is fine for testing, which makes things appear simpler than they really are).</li>
<li>There are lots of caveats with the config servers, so read <a href="http://www.mongodb.org/display/DOCS/Changing+Config+Servers">Changing Config Servers</a> carefully before configuring your cluster.</li>
<li>Otherwise these mongod instances are fairly blackboxish to me. Despite being mongod processes you administer them completely differently.</li>
</ul>
<p><b>mongos routers</b></p>
<ul>
<li>1 per app server. This wouldn&#8217;t be a big deal <a href="http://www.mongodb.org/display/DOCS/flushRouterConfig+command">except that our mongoses often start failing and require flushRouterConfig to be run on them</a>. <a href="https://jira.mongodb.org/browse/SERVER-3739">2.0.1 supposedly fixes this</a>, but we haven&#8217;t tested that yet (and trading known problems for new unknown ones is always scary).</li>
<li>mongos instances can use a lot of CPU and seem to have random spikes where they fully utilize every core very briefly. Keep this in mind if your application servers are already CPU bound.</li>
<li>On the bright side mongos balanced our data rather quickly. Our shard key is a uuid, and it properly setup reasonable ranges in very short order without having to preconfigure them.</li>
<li>&#8220;mongos&#8221; is a terribly confusing name. It sounds like multiple mongo instances. We&#8217;ve taken to calling them mongooses internally due to frequent typos and confusion.</li>
</ul>
<p><b>arbiters</b></p>
<ul>
<li>You need at least 3 members in a replica set in order to complete an election if 1 member goes down.</li>
<li>We haven&#8217;t had any issues with arbiters&#8230; not sure what we&#8217;d do if one broke somehow but since they have no persistent data they&#8217;re safe to restart at any time.</li>
</ul>
<p><b>mongods</b></p>
<ul>
<li>Early on we ran into a problem where changing replica set member entries wasn&#8217;t propagated to the config servers&#8217; shard configuration. Restarting every mongos fixed it.</li>
<li>As far as I can tell a new replica set member will never leave the initial RECOVERING state until all operations to that set are stopped. Even 40 updates per second was enough of a trickle to prevent a new set member from leaving RECOVERING to becoming a SECONDARY. We had to shutdown mongoses to cut off all traffic to bring up a new member. (The replication log gave every indication of being caught up and our usual update load is thousands per second.)</li>
<li>Setting rest in the config file doesn&#8217;t seem to work. Put &#8211;rest in your command line options.</li>
<li>Sending an HTTP request to a mongod&#8217;s main port (instead of the HTTP endpoint) seems to be capable of crashing the mongod.</li>
</ul>
<p><b>Client Drivers</b></p>
<p>While a single replica set member was in a RECOVERING state our Java services couldn&#8217;t complete <i>any</i> operations while our Python service was happily working away.</p>
<p><b>Summary</b></p>
<p>Right now we&#8217;re getting by with 2 shards on 2 dedicated servers and then mongoses and config servers spread throughout other servers. There appears to be some data loss occurring, though due to the ephemeral fast changing nature of this dataset it&#8217;s very difficult to determine definitively or reproduce independently.</p>
<p>So we&#8217;re trying to migrate off of MongoDB to a custom service better suited for this dataset ASAP.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.schmichael.com/2011/11/05/failing-with-mongodb/feed/</wfw:commentRss>
		<slash:comments>40</slash:comments>
		</item>
		<item>
		<title>schmongodb slides from Update Portland</title>
		<link>http://blog.schmichael.com/2011/02/02/schmongodb-slides-from-update-portland/</link>
		<comments>http://blog.schmichael.com/2011/02/02/schmongodb-slides-from-update-portland/#comments</comments>
		<pubDate>Thu, 03 Feb 2011 06:37:29 +0000</pubDate>
		<dc:creator>Michael Schurter</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[updatepdx]]></category>
		<category><![CDATA[urbanairship]]></category>

		<guid isPermaLink="false">http://blog.schmichael.com/?p=895</guid>
		<description><![CDATA[A few months ago someone in #pdxwebdev on Freenode asked an innocent MongoDB question. In response I ranted seemingly endlessly about our experience with MongoDB at Urban Airship. After a few moments somebody (perhaps sarcastically? who can know on IRC) &#8230; <a href="http://blog.schmichael.com/2011/02/02/schmongodb-slides-from-update-portland/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A few months ago someone in #pdxwebdev on Freenode asked an innocent <a href="http://www.mongodb.org">MongoDB</a> question. In response I ranted seemingly endlessly about our experience with MongoDB at <a href="http://urbanairship.com">Urban Airship</a>. After a few moments somebody (perhaps sarcastically? who can know on IRC) suggested I give a talk on my experiences with MongoDB. That led me to realize despite <a href="http://calagator.org/">Portland&#8217;s amazing meetup culture</a> there were no tech-meetups that focused on either:</p>
<ol>
<li>Narrative talks based on experiences in production <small>(<em>not</em> how-tos)</small></li>
<li>Database-agnostic backend systems focused groups <small>(<em>not</em> just a NoSQL meetup)</small></li>
</ol>
<p>So I started one: <a href="http://www.meetup.com/updatepdx/">Update Portland</a>.</p>
<p>And I gave my promised MongoDB talk: <a href="https://docs.google.com/present/view?id=ddzswzbr_104f2sgp8dq">schmongodb</a>.</p>
<p>And <a href="http://twitter.com/meghanpgill/status/23455639216848896">10gen sent swag</a>! (Thanks to <a href="http://twitter.com/meghanpgill">Meghan</a>! It was a big hit.)</p>
<p><em>And</em> my brilliant coworker <a href="http://twitter.com/eonnen">Erik Onnen</a> gave a short talk on how he&#8217;s beginning to use <a href="http://sna-projects.com/kafka/">Kafka</a> at Urban Airship. (Expect a long form talk on that in the future!)</p>
<p>Thanks to everyone who showed up. I had a great time and have high hopes for the upcoming meetings. (Sign up for the <a href="http://groups.google.com/group/update-pdx">mailing list</a>!)</p>
<p>The slides may come across as overly negative. After all Urban Airship is actively moving away from MongoDB for our largest and busiest pieces of data. So I want to make 2 things very clear:</p>
<ol>
<li>I like MongoDB and would like to use it again in the future. There&#8217;s a lot I don&#8217;t like about it, but I can&#8217;t think of any &#8220;perfect&#8221; piece of software.</li>
<li>The IO situation in EC2, particularly EBS&#8217;s poor performance (RAIDing really doesn&#8217;t help) made life with MongoDB miserable. This story may have been very different if we were running MongoDB on bare metal with fast disks.</li>
</ol>
<p><a href="http://www.mikeherrick.com/">Mike Herrick, the VP of Engineering at Urban Airship</a>, put me on the spot at the end of my talk by asking me by asking me: <strong>&#8220;Knowing what you know now, what would you have done differently?&#8221;</strong></p>
<p>I didn&#8217;t have a good answer, and I still don&#8217;t. Despite all of the misadventures, MongoDB wasn&#8217;t the wrong choice. Scaling systems is just hard, and if you want something to work under load, you&#8217;re going to have to learn all of its ins and outs. We initially started moving to Cassandra, and while it has tons of wonderful attributes, we&#8217;re running into plenty of problems with it as well.</p>
<p>So I think the answer is <em>knowing then what I know now</em>. In other words: <strong>Do your homework</strong>. That way we could have avoided these shortcomings and perhaps still be happy with MongoDB today. Hopefully these slides will help others in how they plan to use MongoDB so they can use it properly and happily.</p>
<p><strong>Note:</strong> I added lots of comments to the speaker notes, so you&#8217;ll probably want to view those while looking at the slides.<br />
<iframe src="https://docs.google.com/present/embed?id=ddzswzbr_104f2sgp8dq&#038;size=m" frameborder="0" width="555" height="451"></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.schmichael.com/2011/02/02/schmongodb-slides-from-update-portland/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Less Pagination, More More</title>
		<link>http://blog.schmichael.com/2010/07/16/less-pagination-more-more/</link>
		<comments>http://blog.schmichael.com/2010/07/16/less-pagination-more-more/#comments</comments>
		<pubDate>Sat, 17 Jul 2010 00:30:58 +0000</pubDate>
		<dc:creator>Michael Schurter</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[cassandra]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[urbanairship]]></category>

		<guid isPermaLink="false">http://blog.schmichael.com/?p=827</guid>
		<description><![CDATA[We live in a brave new (to some) world of databases other than a relational database with a SQL interface. Normally end users never notice a difference, but the astute viewer may notice the slow demise of an old friend: &#8230; <a href="http://blog.schmichael.com/2010/07/16/less-pagination-more-more/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>We live in a brave new (to some) world of databases other than a relational database with a SQL interface. Normally end users never notice a difference, but the astute viewer may notice the slow demise of an old friend: pagination.</p>
<p>Traditionally with SQL databases pagination has looked something like this:<br />
<img src="http://schmichael.com/files/pagination.png"/></p>
<p>There are previous and next links as well as links for jumping right to the beginning and end. Pretty boring stuff.</p>
<p>What&#8217;s interesting is that this standard interface is disappearing in favor of something like this:</p>
<p><em>Twitter</em><br />
<img src="http://schmichael.com/files/twitter-more.png"/></p>
<p><em>Facebook</em><br />
<img src="http://schmichael.com/files/facebook-more.png"/></p>
<p>And soon beta testers of <a href="http://blog.urbanairship.com/2010/05/25/android-delivers-push-notifications-are-here-to-stay/">Urban Airship&#8217;s push service for Android</a> will see a More link on the page that lists devices associated with their app:</p>
<p><img src="http://schmichael.com/files/apids-more.png"/></p>
<p>The simplest possible explanation for this dumbing down of pagination is that <strong>count (for total pages) and skip/offset are expensive operations.</strong></p>
<p>Not only are those operations expensive, but in eventually consistent databases, which many modern non-relational databases are, they&#8217;re extremely expensive, if not impossible, to perform.</p>
<p><strong>Cassandra</strong></p>
<p>At Urban Airship we, like Facebook, use <a href="http://cassandra.apache.org/">Cassandra</a>: a distributed column-based database. This deals two deadly blows to traditional pagination:</p>
<ol>
<li>No way to count columns in a row (without reading every column).</li>
<li>No way to skip by numeric offset (so you can&#8217;t say, skip to page 5).</li>
</ol>
<p>In Cassandra columns are ordered, so you start reading from the beginning and read N+1 columns where N is the number of items you&#8217;d like to display. The last column&#8217;s key is then used to determine whether the More link is enabled, and if so, what key to start the next &#8220;page&#8221; at. </p>
<p>Both of those are solvable problems if you really need them, but I would suspect you would end up creating a column count cache as well as some sort of table of contents for the various page offsets. Not what I want to spend my time implementing.</p>
<p>The fact of the matter is that for many use cases, a simple More button works just as well (if not better) than traditional pagination. It&#8217;s also far cheaper to implement, which means more developer time free to work on features and more hardware resources available to push your 140 character insights around the web.</p>
<p><strong>MongoDB</strong></p>
<p>I should note that MongoDB is fairly unique in the non-relational database world as its dynamic querying features include <a href="http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Count">count</a> and <a href="http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bskip%28%29%7D%7D">skip</a> operations. However, as with any database, you&#8217;ll want to make sure these queries hit indexes.</p>
<p>Sadly MongoDB currently doesn&#8217;t have the distributed features necessary to automatically handle data too big for a single server.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.schmichael.com/2010/07/16/less-pagination-more-more/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<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>

