Without a doubt, one of the quickest ways to build an application that leverages MongoDB is with Node. It’s as if the two platforms were made for each other; the sheer number of Node libraries available for dealing with Mongo is testimony to a vibrant, innovative community. Indeed, one of my favorite Mongo focused libraries these days is Mongoose .
Briefly, Mongoose is an object modeling framework that makes it incredibly easy to model collections and ultimately work with intuitive objects that support a rich feature set. Like most things in Node, it couldn’t be any easier to get set up. Essentially, to use Mongoose, you’ll need to define Schema
objects – these are your documents – either top level or even embedded.
For example, I’ve defined a words
collection that contains documents (representing…words) that each contain an embedded collection of definition
documents. A sample document looks like this:
Word Document <span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<code class='javascript'><span class='line'><span class="p">{</span>
</span><span class='line'> <span class="nx">_id</span><span class="o">:</span> <span class="s2">"4fd7c7ac8b5b27f21b000001"</span><span class="p">,</span>
</span><span class='line'> <span class="nx">spelling</span><span class="o">:</span> <span class="s2">"drivel"</span><span class="p">,</span>
</span><span class='line'> <span class="nx">synonyms</span><span class="o">:</span> <span class="p">[</span><span class="s2">"garbage"</span><span class="p">,</span> <span class="s2">"dribble"</span><span class="p">,</span> <span class="s2">"drool"</span><span class="p">],</span>
</span><span class='line'> <span class="nx">definitions</span><span class="o">:</span> <span class="p">[</span>
</span><span class='line'> <span class="p">{</span> <span class="nx">part_of_speech</span><span class="o">:</span> <span class="s2">"noun"</span><span class="p">,</span>
</span><span class='line'> <span class="nx">definition</span><span class="o">:</span><span class="s2">"saliva flowing from the mouth, or mucus from the nose; slaver."</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'> <span class="p">{</span> <span class="nx">part_of_speech</span><span class="o">:</span> <span class="s2">"noun"</span><span class="p">,</span>
</span><span class='line'> <span class="nx">definition</span><span class="o">:</span><span class="s2">"childish, silly, or meaningless talk or thinking; nonsense; twaddle."</span>
</span><span class='line'> <span class="p">}]</span>
</span><span class='line'><span class="p">}</span>
</span></code>
From an document modeling standpoint, I’d like to work with a Word
object that contains a list of Definition
objects and a number of related attributes (i.e. synonyms, parts of speech, etc). To model this relationship with Mongoose, I’ll need to define two Schema
types and I’ll start with the simplest:
Definition Schema <span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<code class='javascript'><span class='line'><span class="nx">Definition</span> <span class="o">=</span> <span class="nx">mongoose</span><span class="p">.</span><span class="nx">model</span> <span class="s1">'definition'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">mongoose</span><span class="p">.</span><span class="nx">Schema</span><span class="p">({</span>
</span><span class='line'> <span class="nx">part_of_speech</span> <span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="nx">required</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">trim</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="kr">enum</span><span class="o">:</span> <span class="p">[</span><span class="s1">'adjective'</span><span class="p">,</span> <span class="s1">'noun'</span><span class="p">,</span> <span class="s1">'verb'</span><span class="p">,</span> <span class="s1">'adverb'</span><span class="p">]</span> <span class="p">},</span>
</span><span class='line'> <span class="nx">definition</span> <span class="o">:</span> <span class="p">{</span><span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="nx">required</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">trim</span><span class="o">:</span> <span class="kc">true</span><span class="p">}</span>
</span><span class='line'><span class="p">})</span>
</span></code>
As you can see, a Definition
is simple – the part_of_speech
attribute is an enumerated String
that’s required; what’s more, the definition
attribute is also a required String
.
Next, I’ll define a Word
:
Word Schema <span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<code class='javascript'><span class='line'><span class="nx">Word</span> <span class="o">=</span> <span class="nx">mongoose</span><span class="p">.</span><span class="nx">model</span> <span class="s1">'word'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">mongoose</span><span class="p">.</span><span class="nx">Schema</span><span class="p">({</span>
</span><span class='line'> <span class="nx">spelling</span> <span class="o">:</span> <span class="p">{</span><span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="nx">required</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">trim</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">lowercase</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">unique</span><span class="o">:</span> <span class="kc">true</span><span class="p">},</span>
</span><span class='line'> <span class="nx">definitions</span> <span class="o">:</span> <span class="p">[</span><span class="nx">Definition</span><span class="p">.</span><span class="nx">schema</span><span class="p">],</span>
</span><span class='line'> <span class="nx">synonyms</span> <span class="o">:</span> <span class="p">[{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="nx">trim</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">lowercase</span><span class="o">:</span> <span class="kc">true</span> <span class="p">}]</span>
</span><span class='line'><span class="p">})</span>
</span></code>
As you can see, a Word
instance embeds a collection of Definition
s. Here I’m also demonstrating the usage of lowercase
and the index unique
placed on the spelling
attribute.
To create a Word
instance and save the corresponding document couldn’t be easier. Mongo array’s leverage the push
command and Mongoose follows this pattern to the tee.
saving with Mongoose <span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<code class='javascript'><span class='line'><span class="nx">word</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">models</span><span class="p">.</span><span class="nx">Word</span><span class="p">({</span><span class="nx">spelling</span> <span class="o">:</span> <span class="s1">'loquacious'</span><span class="p">})</span>
</span><span class='line'><span class="nx">word</span><span class="p">.</span><span class="nx">synonyms</span><span class="p">.</span><span class="nx">push</span> <span class="s1">'verbose'</span>
</span><span class='line'><span class="nx">word</span><span class="p">.</span><span class="nx">definitions</span><span class="p">.</span><span class="nx">push</span> <span class="p">{</span><span class="nx">definition</span><span class="o">:</span> <span class="s1">'talking or tending to talk much or freely; talkative; \</span>
</span><span class='line'><span class="s1"> chattering; babbling; garrulous.'</span><span class="p">,</span> <span class="nx">part_of_speech</span><span class="o">:</span> <span class="s1">'adjective'</span> <span class="p">}</span>
</span><span class='line'><span class="nx">word</span><span class="p">.</span><span class="nx">save</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="o">-></span>
</span></code>
Finding a word is easy too:
findOne in action <span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<code class='javascript'><span class='line'><span class="nx">it</span> <span class="s1">'findOne should return one'</span><span class="p">,</span> <span class="p">(</span><span class="nx">done</span><span class="p">)</span> <span class="o">-></span>
</span><span class='line'> <span class="nx">models</span><span class="p">.</span><span class="nx">Word</span><span class="p">.</span><span class="nx">findOne</span> <span class="nx">spelling</span><span class="o">:</span><span class="s1">'nefarious'</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nb">document</span><span class="p">)</span> <span class="o">-></span>
</span><span class='line'> <span class="nb">document</span><span class="p">.</span><span class="nx">spelling</span><span class="p">.</span><span class="nx">should</span><span class="p">.</span><span class="nx">eql</span> <span class="s1">'nefarious'</span>
</span><span class='line'> <span class="nb">document</span><span class="p">.</span><span class="nx">definitions</span><span class="p">.</span><span class="nx">length</span><span class="p">.</span><span class="nx">should</span><span class="p">.</span><span class="nx">eql</span> <span class="mi">1</span>
</span><span class='line'> <span class="nb">document</span><span class="p">.</span><span class="nx">synonyms</span><span class="p">.</span><span class="nx">length</span><span class="p">.</span><span class="nx">should</span><span class="p">.</span><span class="nx">eql</span> <span class="mi">2</span>
</span><span class='line'> <span class="nb">document</span><span class="p">.</span><span class="nx">definitions</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">'part_of_speech'</span><span class="p">].</span><span class="nx">should</span><span class="p">.</span><span class="nx">eql</span> <span class="s1">'adjective'</span>
</span><span class='line'> <span class="nx">done</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
</span></code>
In this case, the above code is a Mocha test case (which uses should for assertions) that demonstrates Mongoose’s findOne
.
You can find the code for these examples and more at my Github repo dubbed Exegesis and while you’re at it, check out the developerWorks videos I did for Node !