<?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>M. E. Patterson - Author, Geek &#187; mongodb</title>
	<atom:link href="http://mepatterson.net/tag/mongodb/feed/" rel="self" type="application/rss+xml" />
	<link>http://mepatterson.net</link>
	<description>bestselling author of Devil&#039;s Hand, a supernatural thriller; writer of fictions and web software</description>
	<lastBuildDate>Sun, 18 Dec 2011 23:19:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
	<!-- google_ad_section_end --><!-- google_ad_section_start -->	<item>
		<title>SQL/NoSQL Debate? Why?</title>
		<link>http://mepatterson.net/2011/05/sqlnosql-debate-why/</link>
		<comments>http://mepatterson.net/2011/05/sqlnosql-debate-why/#comments</comments>
		<pubDate>Fri, 27 May 2011 14:03:37 +0000</pubDate>
		<dc:creator>M. E. Patterson</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[databases]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://blog.digimonkey.com/?p=194</guid>
		<description><![CDATA[Short post here. I&#8217;m tired of hearing about the SQL/NoSQL &#8220;debate.&#8221; Seriously. I don&#8217;t really understand why there&#8217;s a need to stake out territory and then start a war over techno-ideologies. In my opinion, this debate is like having a debate about cars vs. pickup trucks. There are valid pros/cons to buying cars and valid [...]]]></description>
			<content:encoded><![CDATA[<p>Short post here. I&#8217;m tired of hearing about the SQL/NoSQL &#8220;debate.&#8221; Seriously. I don&#8217;t really understand why there&#8217;s a need to stake out territory and then start a war over techno-ideologies.</p>
<p>In my opinion, this debate is like having a debate about cars vs. pickup trucks. There are valid pros/cons to buying cars and valid pros/cons to buying pickup trucks. In fact, it&#8217;s totally valid for one person to own both a car and a pickup truck! Gasp! I know, it&#8217;s mind-blowing!</p>
<p>I&#8217;ll add that, as a proponent of <a href="http://www.mongodb.org/">MongoDB</a>, I definitely think the right NoSQL database is a better solution in many ways for much of the web-app databasing that was previously handled by relational DBs. But my saying that in no way indicates that I think SQL is dead, relational is dead, or anything of that sort. This is a classic &#8216;right tools for the job&#8217; discussion.</p>
<p>If there&#8217;s any debate at all, maybe it&#8217;s around what, specifically, the best use cases are for each type of database, but I&#8217;d prefer that we stop referring to that as a debate and instead just see it as an ongoing evolution and discussion. Creating conflict where there doesn&#8217;t need to be any solves nothing and makes us all look bad.</p>
]]></content:encoded>
			<wfw:commentRss>http://mepatterson.net/2011/05/sqlnosql-debate-why/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Starting a new Rails app?  Here&#8217;s my skeleton&#8230;</title>
		<link>http://mepatterson.net/2010/02/starting-a-new-rails-app-heres-my-skeleton/</link>
		<comments>http://mepatterson.net/2010/02/starting-a-new-rails-app-heres-my-skeleton/#comments</comments>
		<pubDate>Mon, 15 Feb 2010 20:02:19 +0000</pubDate>
		<dc:creator>M. E. Patterson</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[gems]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[mongomapper]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http://blog.digimonkey.com/?p=81</guid>
		<description><![CDATA[Not meant to be a &#8220;this is what should be done&#8221; as much as a &#8220;this is what Matt uses, based largely on community popularity, best practice, and Matt&#8217;s personal tastes.&#8221; Take it for what it is: a point of discussion. Of course, the skeleton of any Rails app will vary from project to project, [...]]]></description>
			<content:encoded><![CDATA[<p>Not meant to be a &#8220;this is what should be done&#8221; as much as a &#8220;this is what Matt uses, based largely on community popularity, best practice, and Matt&#8217;s personal tastes.&#8221;</p>
<p>Take it for what it is: a point of discussion.</p>
<p>Of course, the skeleton of any Rails app will vary from project to project, depending on needs.  Agile approach is to only add it to your framework if you actually need it <em>right now</em>, though some stuff tends to be easier to use (like authentication systems and databases) if you build it in up-front.  That tends to be my approach for green-fielding Rails apps.</p>
<p>If you&#8217;ve got some favorites that <em>you</em> use, feel free to post in the comments about it!  I&#8217;m always interested in hearing about new stuff that makes my life easier/more fun.<br />
<span id="more-81"></span></p>
<h3>FOR MY ACTIVERECORD-BASED APPS</h3>
<ul>
<li> <strong>inherited_resources</strong>
<ul>
<li> for building clean, simple resource-oriented controllers.  the Rails 3.0 guys <a id="j8wo" title="recommend you start using this" href="http://www.enlightsolutions.com/articles/five-ways-to-prepare-your-application-for-ruby-on-rails-3-today/">recommend you start using this</a> with Rails 2.3.5 apps because Rails 3.0&#8242;s new controller syntax is basically derived from inherited_resources (and jose valim is on the rails core team now)</li>
</ul>
</li>
<li> <strong>authlogic</strong>
<ul>
<li> the reigning champ (in my opinion) for a while in terms of a really simple, basic user authentication solution.  i&#8217;ve also tried clearance, lockdown, ye olde restful_authentication, and others.  I still like authlogic alot, but the new Devise system seems to be really solid and might be good enough to get me to switch for new apps</li>
</ul>
</li>
<li> <strong>searchlogic</strong>
<ul>
<li> really handy extra methods for activerecord queries</li>
</ul>
</li>
<li> <strong>haml / sass</strong>
<ul>
<li> blah blah blah <a href="http://blog.digimonkey.com/2010/02/why-use-haml-and-sass-i-already-know-html/">http://blog.digimonkey.com/2010/02/why-use-haml-and-sass-i-already-know-html/ </a></li>
</ul>
</li>
<li> <strong>formtastic</strong> &#8212; <a href="http://github.com/justinfrench/formtastic">http://github.com/justinfrench/formtastic</a>
<ul>
<li> if you intend to produce semantically-correct, standards-compliant xhtml, your biggest enemy is trying to get forms to both look right and be semantic xhtml.  formtastic takes you a long way towards that goal, while also cleaning up your views significantly. and if you need to do something weird for a form that doesn&#8217;t quite work with formtastic, it doesn&#8217;t get in your way.</li>
</ul>
</li>
<li> <strong>compass + blueprint</strong>
<ul>
<li> blueprint is just a CSS framework for laying out 950px wide fixed layouts in a clean way; particularly great for multi-column layouts, which can be notoriously tricky to get right and cross-browser</li>
<li> compass adds a layer on top of blueprint + Sass to make html/css design really easy and slick; saves you a TON of time and makes it easier to get the cross-browser stuff working (or 99% working) on the first try, instead of spending a whole day fighting IE 7</li>
</ul>
</li>
<li> <strong>hoptoad</strong>
<ul>
<li> exception notification to a third-party service that integrates with lighthouse, github, et al</li>
</ul>
</li>
<li> <strong>acts_as_state_machine</strong>
<ul>
<li> self-explanatory</li>
</ul>
</li>
<li> <strong>acts_as_taggable_on_steroids</strong></li>
<li> <strong>acts_as_rateable_with_weights</strong> (mine) &#8211; <a id="u20v" title="http://github.com/mepatterson/acts_as_rateable_with_weights" href="http://github.com/mepatterson/acts_as_rateable_with_weights">http://github.com/mepatterson/acts_as_rateable_with_weights</a>
<ul>
<li> forked my own version of acts_as_rateable to add weighted ratings and bayesian averages</li>
</ul>
</li>
<li> <strong>will_paginate</strong>
<ul>
<li> makes it much easier to handle pagination on <em>any </em>enumerable object collection (ActiveRecord objects or not)</li>
</ul>
</li>
<li> <strong>ssl_requirement</strong>
<ul>
<li> allows you to lock down controller methods so they won&#8217;t work unless the requestor is hitting them through SSL</li>
</ul>
</li>
<li> <strong>statistics</strong> &#8211; <a id="zf5s" title="http://github.com/acatighera/statistics" href="http://github.com/acatighera/statistics">http://github.com/acatighera/statistics</a>
<ul>
<li> have used this exactly once.  liked it, but didn&#8217;t use a ton of its features.  seems pretty robust though.</li>
</ul>
</li>
<li> <strong>jrails</strong> plugin (+ nuke the prototype stuff and replace with jquery)
<ul>
<li> self-explanatory; prototype is dead. long live jquery.</li>
</ul>
</li>
<li> <strong>xapian</strong> or <strong>thinking_sphinx</strong>
<ul>
<li> i&#8217;ve gone through so many different search engines for so many projects.  I think I&#8217;m the only one using Xapian.  It actually works pretty well, but is lacking in a lot of ways.  Thinking sphinx is similar; easier Rails integration, but missing some stuff, though it&#8217;s highlighting and excerpting work nicely.</li>
</ul>
</li>
<li> <strong>paperclip</strong>
<ul>
<li> super-simple file attachments on ActiveRecord models</li>
</ul>
</li>
<li> <strong>carmen</strong> &#8212; <a id="nu18" title="http://github.com/jim/carmen" href="http://github.com/jim/carmen">http://github.com/jim/carmen</a>
<ul>
<li> &#8220;helpful collection of geographic names and abbreviations for Rails apps (includes replacements for country_select and state_select)&#8221;</li>
</ul>
</li>
<li> <strong>stringex</strong> &#8212; <a id="fv2l" title="http://github.com/rsl/stringex" href="http://github.com/rsl/stringex">http://github.com/rsl/stringex</a>
<ul>
<li> helpful assortment of extra string methods</li>
</ul>
</li>
<li> <strong>admin-data</strong> &#8212; <a id="qqkd" title="http://github.com/neerajdotname/admin_data" href="http://github.com/neerajdotname/admin_data">http://github.com/neerajdotname/admin_data</a>
<ul>
<li> every app ends up needing some sort of admin backend to rifle through the data layer, at the very least in development mode; pretty useful</li>
</ul>
</li>
<li> <strong>bullet</strong> &#8212; <a id="agmh" title="http://github.com/flyerhzm/bullet" href="http://github.com/flyerhzm/bullet">http://github.com/flyerhzm/bullet</a>
<ul>
<li> stupid-simple plugin that helps you find N+1 queries and other query performance problems</li>
</ul>
</li>
<li> <strong>factory_girl</strong>, <strong>shoulda</strong>, <strong>faker</strong>
<ul>
<li> i liked factory_girl a lot until my company started using machinist, so now I think I like that better.  shoulda is great.  faker is indispensable, imho.</li>
</ul>
</li>
<li> <strong>db-populate </strong>&#8211; <a id="bxz9" title="http://github.com/ffmike/db-populate" href="http://github.com/ffmike/db-populate">http://github.com/ffmike/db-populate</a>
<ul>
<li> i&#8217;ve been using this in my older AR-backed apps.  probably won&#8217;t need it in 2.3.5 or 3.0 apps, though i do like how ffmike did db-populate.  i think it might still be more robust than the db:seed thing built-in to Rails</li>
</ul>
</li>
</ul>
<h3>FOR MY MONGO_MAPPER APPS</h3>
<ul>
<li> <strong>mongo</strong>
<ul>
<li> [GEM] the base MongoDB ruby driver</li>
</ul>
</li>
<li> <strong>mongo_ext</strong>
<ul>
<li> [GEM] C-extensions for the above to make it perform better</li>
</ul>
</li>
<li> <strong>mongo_mapper</strong>
<ul>
<li> [GEM] John Nunemaker&#8217;s thin ORM layer for Mongo.  fairly young and poorly documented, but it&#8217;s such a thin wrapper that it hasn&#8217;t been a problem for me.  just gives you some basic ActiveRecord-ish relationships and conveniences for using Mongo Documents and EmbeddedDocuments with standard Ruby models.</li>
<li> <a href="http://railstips.org/blog/archives/2009/06/27/mongomapper-the-rad-mongo-wrapper/">http://railstips.org/blog/archives/2009/06/27/mongomapper-the-rad-mongo-wrapper/</a></li>
<li> <a href="http://railstips.org/blog/archives/2009/12/18/why-i-think-mongo-is-to-databases-what-rails-was-to-frameworks/">http://railstips.org/blog/archives/2009/12/18/why-i-think-mongo-is-to-databases-what-rails-was-to-frameworks/</a></li>
<li> <a id="tlav" title="http://rdoc.info/projects/jnunemaker/mongomapper" href="http://rdoc.info/projects/jnunemaker/mongomapper">http://rdoc.info/projects/jnunemaker/mongomapper</a></li>
</ul>
</li>
<li> <strong>sunspot</strong>[GEM] + <strong>sunspot_rails</strong>[GEM] (with custom config for mongo support) &#8211; <a id="yy.0" title="http://github.com/outoftime/sunspot" href="http://github.com/outoftime/sunspot">http://github.com/outoftime/sunspot</a>
<ul>
<li> found that sunspot integrates the solr search engine more easily with mongo than anything else out there.  has a lot of nice features, and it does automatic indexing on the fly, rather than requiring some sort of nasty cron job or handrolled delta-indexing solution</li>
</ul>
</li>
<li> <em>handrolled auth system derived in part from</em> <strong>authlogic</strong>
<ul>
<li> so, i probably should start using Devise, since it apparently has native mongo_mapper support.  but for the two mongo apps I&#8217;ve built thus far, i just handrolled a simple authentication system by adapting the core code from authlogic and removing all the ActiveRecord-specific bits.  works fine, easy to add on custom stuff.  but Devise is probably better for the future.</li>
</ul>
</li>
<li> <strong>machinist</strong>, <strong>shoulda</strong>, <strong>faker</strong>
<ul>
<li> see above</li>
</ul>
</li>
<li> <strong>acts_as_mongo_rateable</strong> (mine) &#8212; <a id="c2pf" title="http://github.com/mepatterson/acts_as_mongo_rateable" href="http://github.com/mepatterson/acts_as_mongo_rateable">http://github.com/mepatterson/acts_as_mongo_rateable</a>
<ul>
<li> I wrote this from scratch, inspired by the basic architecture of the acts_as_rateable plugin for ActiveRecord</li>
</ul>
</li>
<li> <strong>acts_as_mongo_taggable</strong> (mine) &#8211; <a id="hu4g" title="http://github.com/mepatterson/acts_as_mongo_taggable" href="http://github.com/mepatterson/acts_as_mongo_taggable">http://github.com/mepatterson/acts_as_mongo_taggable</a>
<ul>
<li> I wrote this from scratch, inspired by the basic architecture of the acts_as_taggable_on_steroids plugin for ActiveRecord</li>
</ul>
</li>
<li> <strong>will_paginate</strong>
<ul>
<li> works fine with any enumerable object, so works with Mongo</li>
</ul>
</li>
<li> <strong>compass</strong> + <strong>blueprint</strong>
<ul>
<li> see above</li>
</ul>
</li>
<li> <strong>haml</strong> / <strong>sass</strong>
<ul>
<li> see above</li>
</ul>
</li>
<li> <strong>jrails</strong> plugin (+ jquery instead of prototype)
<ul>
<li> see above</li>
</ul>
</li>
<li> <strong>inherited_resources</strong>
<ul>
<li> this works largely the same with Mongo, since your resource-based controller shouldn&#8217;t really have any direct dependence on your database ORM</li>
</ul>
</li>
<li> <strong>hoptoad</strong>
<ul>
<li> see above</li>
</ul>
</li>
</ul>
<h3>STUFF I&#8217;D LIKE TO USE/WANT TO INVESTIGATE FURTHER</h3>
<ul>
<li> <strong>devise</strong> &#8211; <a id="bkx-" title="http://github.com/plataformatec/devise" href="http://github.com/plataformatec/devise">http://github.com/plataformatec/devise</a>
<ul>
<li> has mongo support baked in!  looks really cool and has a lot of robust functionality.</li>
<li> example using with mongomapper &#8211; <a id="hpu." title="http://github.com/theshortcut/devise_mongomapper_example" href="http://github.com/theshortcut/devise_mongomapper_example">http://github.com/theshortcut/devise_mongomapper_example</a></li>
</ul>
</li>
<li> <strong>easy ESI</strong> &#8212; <a id="c_ix" title="http://github.com/grosser/easy_esi" href="http://github.com/grosser/easy_esi">http://github.com/grosser/easy_esi</a>
<ul>
<li> haven&#8217;t looked at it much; seems like an interesting approach</li>
</ul>
</li>
<li> <strong>aegis</strong> &#8211; <a id="g-bj" title="http://github.com/makandra/aegis" href="http://github.com/makandra/aegis">http://github.com/makandra/aegis</a>
<ul>
<li> seems like a really nice way to do complicated roles and permissions.  haven&#8217;t used it though.  dunno if it will work with any of the good auth systems like devise, clearance, authlogic, etc.  in most cases, might just be easier to write your own simple roles system (which is what i&#8217;ve done in ALL cases)</li>
</ul>
</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://mepatterson.net/2010/02/starting-a-new-rails-app-heres-my-skeleton/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Mongo Beauty #1</title>
		<link>http://mepatterson.net/2010/02/mongo-beauty-1/</link>
		<comments>http://mepatterson.net/2010/02/mongo-beauty-1/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 05:29:23 +0000</pubDate>
		<dc:creator>M. E. Patterson</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[mongomapper]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://blog.digimonkey.com/?p=64</guid>
		<description><![CDATA[Frequently, while working with MongoDB and MongoMapper, I run across an implementation of something that blows me away with its beauty. This, my friends, is one of those times. Given: a Users collection where the users&#8217; names are stored in an Array key called name. i.e. :name => ["Patterson", "Matt"]. It can be any length, [...]]]></description>
			<content:encoded><![CDATA[<p>Frequently, while working with MongoDB and MongoMapper, I run across an implementation of something that blows me away with its beauty.  This, my friends, is one of those times.  </p>
<p>Given: a Users collection where the users&#8217; names are stored in an Array key called name.  i.e. :name => ["Patterson", "Matt"].  It can be any length, so if they want middle names or titles or whatever, it just gets stuck in there as an element on the array.</p>
<p>Problem: Need to create a really quick lookup to do autocomplete when someone is looking for a particular person in the database.</p>
<p>Solution:</p>
<div class="codecolorer-container ruby blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">named</span><span style="color:#006600; font-weight:bold;">&#40;</span>query<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; User.<span style="color:#9900CC;">all</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:name</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">/</span>^<span style="color:#008000; font-style:italic;">#{query}.*/i })</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div></div>
<p>So when the user types &#8220;m&#8221; into the autocomplete field, it will quickly populate the suggestions with ["Patterson", "Matt"] and ["Magdalene", "Mary"] and ["Munchausen", "Baron"] and ["Mr.", "John", "Arbuckle"].  But it won&#8217;t pickup people with &#8216;m&#8217; in the middle of any of their name components, like ["Hammer", "Captain"].</p>
<p>How simple is that?</p>
<p>UPDATE: 11 Apr 2010<br />
As it turns out, you can make the above even <em>faster</em>:</p>
<div class="codecolorer-container ruby blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">named</span><span style="color:#006600; font-weight:bold;">&#40;</span>query<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; User.<span style="color:#9900CC;">all</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:name</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">/</span>^<span style="color:#008000; font-style:italic;">#{query}/i })</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div></div>
<p>without the &#8216;.*&#8217; bit, apparently mongo&#8217;s regex implementation gets a huge speed boost since it&#8217;s not having to parse the rest of the string once it hits a match.</p>
]]></content:encoded>
			<wfw:commentRss>http://mepatterson.net/2010/02/mongo-beauty-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Mongosphinx with MongoDB and MongoMapper</title>
		<link>http://mepatterson.net/2010/01/mongosphinx-with-mongodb-and-mongomapper/</link>
		<comments>http://mepatterson.net/2010/01/mongosphinx-with-mongodb-and-mongomapper/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 23:29:53 +0000</pubDate>
		<dc:creator>M. E. Patterson</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[sphinx]]></category>

		<guid isPermaLink="false">http://blog.digimonkey.com/?p=43</guid>
		<description><![CDATA[Can that title have the word &#8216;mongo&#8217; in it any more times? Well, fear not, I&#8217;m about to use it even more&#8230; So, I had to fool around a bit to get the so-called &#8220;Mongosphinx&#8221; gem working with my app architecture. Thought it might be helpful to others to demonstrate how I did it. I&#8217;ll [...]]]></description>
			<content:encoded><![CDATA[<p><em>Can that title have the word &#8216;mongo&#8217; in it any more times?  Well, fear not, I&#8217;m about to use it even more&#8230;</em></p>
<p>So, I had to fool around a bit to get the so-called &#8220;Mongosphinx&#8221; gem working with my app architecture.  Thought it might be helpful to others to demonstrate how I did it.  I&#8217;ll boil it down to a generic sort of implementation.  Hit the jump to see the whole bloody mess&#8230;<br />
<span id="more-43"></span></p>
<h2>app/models/document.rb</h2>
<div class="codecolorer-container ruby blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#9966CC; font-weight:bold;">class</span> Document<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">include</span> <span style="color:#6666ff; font-weight:bold;">MongoMapper::Document</span><br />
&nbsp; key <span style="color:#ff3333; font-weight:bold;">:title</span>, &nbsp;<span style="color:#CC0066; font-weight:bold;">String</span><br />
&nbsp; key <span style="color:#ff3333; font-weight:bold;">:content</span>, &nbsp;<span style="color:#CC0066; font-weight:bold;">String</span><br />
&nbsp; timestamps!<br />
<br />
&nbsp; <span style="color:#008000; font-style:italic;">#cached for the sphinx indexer</span><br />
&nbsp; key <span style="color:#ff3333; font-weight:bold;">:sphinx_tags</span>, <span style="color:#CC0066; font-weight:bold;">String</span><br />
<br />
&nbsp; <span style="color:#008000; font-style:italic;"># for mongosphinx</span><br />
&nbsp; fulltext_index <span style="color:#ff3333; font-weight:bold;">:title</span>, <span style="color:#ff3333; font-weight:bold;">:content</span><br />
&nbsp; REINDEX_INTERVAL = <span style="color:#006666;">10</span>.<span style="color:#9900CC;">minutes</span><br />
&nbsp; INDEXED_FIELDS = <span style="color:#996600;">'_sphinx_id, title, content, sphinx_tags'</span><br />
&nbsp; before_save: cache_for_indexer<br />
&nbsp; after_save: reindex<br />
<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">search</span><span style="color:#006600; font-weight:bold;">&#40;</span>query<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># method returns a sphinx resultset object with its own each() method</span><br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># iterate over that and pull each element out as an old-fashioned array of Documents</span><br />
&nbsp; &nbsp; by_fulltext_index<span style="color:#006600; font-weight:bold;">&#40;</span>query<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span><span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">|</span><span style="color:#CC0066; font-weight:bold;">p</span><span style="color:#006600; font-weight:bold;">|</span> <span style="color:#CC0066; font-weight:bold;">p</span><span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">xml_for_sphinx_pipe</span><br />
&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#6666ff; font-weight:bold;">MongoSphinx::Indexer::XMLDocset</span>.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>Document.<span style="color:#9900CC;">all</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:fields</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> INDEXED_FIELDS<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">to_s</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> cache_for_indexer<br />
&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">sphinx_tags</span> = tag_words.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">' '</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">true</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> reindex<br />
&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'mongo/gridfs'</span><br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># we run this method whenever a doc is saved, but we only actually reindex every 10 minutes, max</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">unless</span> RAILS_ENV == <span style="color:#996600;">'test'</span><br />
&nbsp; &nbsp; &nbsp; db = MongoMapper.<span style="color:#9900CC;">database</span><br />
&nbsp; &nbsp; &nbsp; file = <span style="color:#996600;">&quot;indexer_next_run&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#6666ff; font-weight:bold;">GridFS::GridStore</span>.<span style="color:#9900CC;">exist</span>?<span style="color:#006600; font-weight:bold;">&#40;</span>db, file<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; line = <span style="color:#6666ff; font-weight:bold;">GridFS::GridStore</span>.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>db, file, <span style="color:#996600;">'r'</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#CC0066; font-weight:bold;">readlines</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> <span style="color:#0000FF; font-weight:bold;">false</span> <span style="color:#9966CC; font-weight:bold;">unless</span> <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span> <span style="color:#006600; font-weight:bold;">&gt;</span> <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">parse</span><span style="color:#006600; font-weight:bold;">&#40;</span>line<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; &nbsp; next_run = <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span> <span style="color:#006600; font-weight:bold;">+</span> REINDEX_INTERVAL<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">to_s</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#6666ff; font-weight:bold;">GridFS::GridStore</span>.<span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">&#40;</span>db, file, <span style="color:#996600;">'w'</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>f<span style="color:#006600; font-weight:bold;">|</span> f.<span style="color:#CC0066; font-weight:bold;">puts</span> next_run <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; logger.<span style="color:#9900CC;">info</span> <span style="color:#996600;">&quot;Running document re-indexer&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#CC00FF; font-weight:bold;">Process</span>.<span style="color:#CC0066; font-weight:bold;">fork</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#996600;">`rake sphinx:index rotate=true`</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></div>
<p>I&#8217;ll illuminate some of that for you.</p>
<p>If you&#8217;ve been using MongoMapper, most of the key stuff should be obvious already.  The &#8216;sphinx_tags&#8217; is a special trick I cooked up to make this work well with my <a href="http://github.com/mepatterson/acts_as_mongo_taggable">acts_as_mongo_taggable</a> plugin.  Basically, whenever a Document is saved/updated, I jam a single string into the sphinx_tags field in Mongo.  This lets sphinx index those tags easily.</p>
<p>The search just takes advantage of Mongosphinx&#8217;s normal by_fulltext_index method.</p>
<p>The reindex thing, while probably a hacky solution, works well enough for now that I don&#8217;t have a need to do anything fancier.  This lets us have the app be reasonably quick to include newly-created documents in the index to be available for search.  And I take advantage of GridFS (built into Mongo) to store my last_run value so I don&#8217;t even need a cron job for this.  If my app starts getting significant document-creation traffic, I might want to do something more sophisticated like delta indexing or whatnot, but for now this is fine for me.</p>
<h2>lib/tasks/sphinx.rake</h2>
<p>Okay, moving on to the aforementioned rake tasks&#8230; Here are the contents of my lib/tasks/sphinx.rake file:</p>
<div class="codecolorer-container ruby blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">namespace <span style="color:#ff3333; font-weight:bold;">:sphinx</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; desc <span style="color:#996600;">&quot;generate xml that is sphinx-friendly&quot;</span><br />
&nbsp; task <span style="color:#ff3333; font-weight:bold;">:genxml</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:environment</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># this will just puts() to stdout; useful for debugging</span><br />
&nbsp; &nbsp; Document.<span style="color:#9900CC;">xml_for_sphinx_pipe</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <br />
&nbsp; desc <span style="color:#996600;">&quot;start up the sphinx daemon&quot;</span><br />
&nbsp; task <span style="color:#ff3333; font-weight:bold;">:start</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:environment</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; cmd = <span style="color:#006600; font-weight:bold;">%</span><span style="color:#006600; font-weight:bold;">&#40;</span> searchd <span style="color:#006600; font-weight:bold;">--</span>config <span style="color:#996600;">&quot;#{Rails.root}/config/sphinx.conf&quot;</span> <span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">system</span>! cmd<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <br />
&nbsp; desc <span style="color:#996600;">&quot;stop the sphinx daemon&quot;</span><br />
&nbsp; task <span style="color:#ff3333; font-weight:bold;">:stop</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:environment</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">system</span>! <span style="color:#006600; font-weight:bold;">%</span><span style="color:#006600; font-weight:bold;">&#40;</span> searchd <span style="color:#006600; font-weight:bold;">--</span>config <span style="color:#996600;">&quot;#{Rails.root}/config/sphinx.conf&quot;</span> <span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <br />
&nbsp; desc <span style="color:#996600;">&quot;run the sphinx indexer&quot;</span><br />
&nbsp; task <span style="color:#ff3333; font-weight:bold;">:index</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:environment</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; cmd = <span style="color:#006600; font-weight:bold;">%</span><span style="color:#006600; font-weight:bold;">&#40;</span> indexer <span style="color:#006600; font-weight:bold;">--</span>config <span style="color:#996600;">&quot;#{Rails.root}/config/sphinx.conf&quot;</span> <span style="color:#006600; font-weight:bold;">--</span>all <span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; cmd <span style="color:#006600; font-weight:bold;">&lt;&lt;</span> <span style="color:#996600;">' --rotate'</span> <span style="color:#9966CC; font-weight:bold;">if</span> ENV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'rotate'</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">&amp;&amp;</span> ENV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'rotate'</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">downcase</span> == <span style="color:#996600;">'true'</span><br />
&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">system</span>! cmd<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
<span style="color:#008000; font-style:italic;"># a fail-fast, hopefully helpful version of system</span><br />
<span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#CC0066; font-weight:bold;">system</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>cmd<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">unless</span> <span style="color:#CC0066; font-weight:bold;">system</span><span style="color:#006600; font-weight:bold;">&#40;</span>cmd<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">raise</span> <span style="color:#006600; font-weight:bold;">&lt;&lt;-</span>SYSTEM_CALL_FAILED<br />
The following command failed:<br />
&nbsp; <span style="color:#008000; font-style:italic;">#{cmd}</span><br />
SYSTEM_CALL_FAILED<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></div>
<p>So this should be pretty self-explanatory, especially if you&#8217;ve already used acts_as_sphinx with a standard ActiveRecord-backed app.  After you&#8217;ve gotten everything (sphinx and the <a href="http://github.com/dacort/mongosphinx">mongosphinx gem</a>, specifically) installed, you should be able to use these rake tasks to start and stop the searchd daemon, as well as run the indexer.</p>
<p>(update 1/22/10: Note that I&#8217;m suggesting you get dacort&#8217;s fork of mongosphinx.  He&#8217;s done a nice job of adding excerpting, pagination, and better compatibility with the latest mongomapper.  He also pulled in my fix that makes it play nice with ruby 1.9.)</p>
<p>One nicety here is the sphinx:genxml task.  Running this is helpful when you&#8217;re trying to get everything setup, to prove that you&#8217;ve done things right.  It should output a big XML file of all the documents it would index.  If it doesn&#8217;t, or you get something weird, then <a href="http://icanhascheezburger.files.wordpress.com/2007/04/wrong-mike.jpg">ur doin&#8217; it wrong</a>.</p>
<h2>config/sphinx.conf</h2>
<p>Finally, to help you get up and running, here&#8217;s my config/sphinx.conf file.  Pretty standard:</p>
<div class="codecolorer-container bash blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">searchd <span style="color: #7a0874; font-weight: bold;">&#123;</span><br />
&nbsp; listen = 127.0.0.1<br />
&nbsp; port = <span style="color: #000000;">9312</span><br />
<br />
&nbsp; log = .<span style="color: #000000; font-weight: bold;">/</span>sphinx<span style="color: #000000; font-weight: bold;">/</span>searchd.log<br />
&nbsp; query_log = .<span style="color: #000000; font-weight: bold;">/</span>sphinx<span style="color: #000000; font-weight: bold;">/</span>searchd.query.log<br />
&nbsp; pid_file = .<span style="color: #000000; font-weight: bold;">/</span>sphinx<span style="color: #000000; font-weight: bold;">/</span>searchd.pid<br />
<span style="color: #7a0874; font-weight: bold;">&#125;</span><br />
<br />
<span style="color: #7a0874; font-weight: bold;">source</span> mongo_project <span style="color: #7a0874; font-weight: bold;">&#123;</span><br />
&nbsp; <span style="color: #7a0874; font-weight: bold;">type</span> = xmlpipe2<br />
<br />
&nbsp; xmlpipe_command = .<span style="color: #000000; font-weight: bold;">/</span>script<span style="color: #000000; font-weight: bold;">/</span>runner <span style="color: #ff0000;">&quot;Document.xml_for_sphinx_pipe&quot;</span><br />
<span style="color: #7a0874; font-weight: bold;">&#125;</span><br />
<br />
index mongo_project <span style="color: #7a0874; font-weight: bold;">&#123;</span><br />
&nbsp; <span style="color: #7a0874; font-weight: bold;">source</span> = mongo_project<br />
<br />
&nbsp; charset_type = utf-<span style="color: #000000;">8</span><br />
&nbsp; path = .<span style="color: #000000; font-weight: bold;">/</span>sphinx<span style="color: #000000; font-weight: bold;">/</span>sphinx_index_main<br />
<span style="color: #7a0874; font-weight: bold;">&#125;</span></div></div>
<p>Again, all of this may fall down spectacularly once you get up to some serious data being pushed from the app into the indexer.  At that point, do something else, something more awesome.  But consider this a basic start on jamming data from your mongo collection(s) right up sphinx&#8217;s pipe.</p>
]]></content:encoded>
			<wfw:commentRss>http://mepatterson.net/2010/01/mongosphinx-with-mongodb-and-mongomapper/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	<!-- google_ad_section_end --></channel>
</rss>

