Skip to content
Browse files

Initial commit

  • Loading branch information...
0 parents commit 73a288b7577b568c4dec6ca35499cbbc11db7acb @banker banker committed Apr 19, 2010
3 .gitignore
@@ -0,0 +1,3 @@
+output
+*.swp
+*.sw0
21 LICENSE
@@ -0,0 +1,21 @@
+The MongoDB Cookbook is inspired by The Redis Cookbook, Copyright (c)
+2010 Ted Nyman [http://ted.io], Tim Lossen [http://tim.lossen.de]
+
+This work is licensed under the Creative Commons Attribution
+Share Alike Unported License (Version 3.0):
+
+http://creativecommons.org/licenses/by_sa/3.0/legalcode
+
+Summary:
+
+You are free to share (to copy, distribute and transmit) and
+to remix (to adapt) this work -- under the following
+conditions:
+
+(a) You must attribute the work in the manner specified by the
+author or licensor (but not in any way that suggests that they
+endorse you or your use of the work).
+
+(b) If you alter, transform, or build upon this work, you may
+distribute the resulting work only under the same, similar or
+a compatible license.
29 README.md
@@ -0,0 +1,29 @@
+# The MongoDB Cookbook
+
+### The ways and hows of MongoDB.
+
+Contribute your patterns, methods, and ideas to the MongoDB Cookbook.
+
+- - -
+
+### How to Contribute a Recipe
+
+1. Fork this repo and create a new topic branch.
+2. Make your addition. See one of the recipe files for a sample.
+3. Send a pull request -- please include a short description of your new or updated recipe.
+4. Enjoy your awesomeness.
+
+### Even More Ways To Contribute
+
+You can:
+
+* Add example code for any existing recipe, in any programming language.
+ Fork the repo and add your code into the relevant directory!
+* Work on the rediscookbook.org website. The site itself is open source and lives in `site`.
+* Look for typos, formatting errors, missing links, and other little things.
+ No potential improvement is 'too small' -- fork for anything.
+
+### License
+
+Creative Commons Attribution Share Alike 3.0
+Inspired by The Redis Cookbook (http://rediscookbook.org)
7 Sitefile
@@ -0,0 +1,7 @@
+
+task :default => :build
+
+desc 'deploy the site to the webserver'
+task :deploy => [:build, 'deploy:rsync']
+
+# EOF
138 content/css/code.css
@@ -0,0 +1,138 @@
+pre.twilight .DiffInserted {
+ background-color: #253B22;
+ color: #F8F8F8;
+}
+pre.twilight .DiffHeader {
+ background-color: #0E2231;
+ color: #F8F8F8;
+ font-style: italic;
+}
+pre.twilight .CssPropertyValue {
+ color: #F9EE98;
+}
+pre.twilight .CCCPreprocessorDirective {
+ color: #AFC4DB;
+}
+pre.twilight .Constant {
+ color: #CF6A4C;
+}
+pre.twilight .DiffChanged {
+ background-color: #4A410D;
+ color: #F8F8F8;
+}
+pre.twilight .EmbeddedSource {
+ background-color: #A3A6AD;
+}
+pre.twilight .Support {
+ color: #9B859D;
+}
+pre.twilight .MarkupList {
+ color: #F9EE98;
+}
+pre.twilight .CssConstructorArgument {
+ color: #8F9D6A;
+}
+pre.twilight .Storage {
+ color: #F9EE98;
+}
+pre.twilight .line-numbers {
+ background-color: #5C5B51;
+ color: #D1D0B8;
+}
+pre.twilight .CssClass {
+ color: #9B703F;
+}
+pre.twilight .StringConstant {
+ color: #DDF2A4;
+}
+pre.twilight .CssAtRule {
+ color: #8693A5;
+}
+pre.twilight .MetaTagInline {
+ color: #E0C589;
+}
+pre.twilight .MarkupHeading {
+ color: #CF6A4C;
+}
+pre.twilight .CssTagName {
+ color: #CDA869;
+}
+pre.twilight .SupportConstant {
+ color: #CF6A4C;
+}
+pre.twilight .DiffDeleted {
+ background-color: #420E09;
+ color: #F8F8F8;
+}
+pre.twilight .CCCPreprocessorLine {
+ color: #8996A8;
+}
+pre.twilight .StringRegexpSpecial {
+ color: #CF7D34;
+}
+pre.twilight .EmbeddedSourceBright {
+ background-color: #9C9EA4;
+}
+pre.twilight .InvalidIllegal {
+ background-color: #241A24;
+ color: #F8F8F8;
+}
+pre.twilight .SupportFunction {
+ color: #DAD085;
+}
+pre.twilight .CssAdditionalConstants {
+ color: #CA7840;
+}
+pre.twilight .MetaTagAll {
+ color: #AC885B;
+}
+pre.twilight .StringRegexp {
+ color: #E9C062;
+}
+pre.twilight .StringEmbeddedSource {
+ color: #DAEFA3;
+}
+pre.twilight .EntityInheritedClass {
+ color: #9B5C2E;
+ font-style: italic;
+}
+pre.twilight .CssId {
+ color: #8B98AB;
+}
+pre.twilight .CssPseudoClass {
+ color: #8F9D6A;
+}
+pre.twilight .StringVariable {
+ color: #8A9A95;
+}
+pre.twilight .String {
+ color: #8F9D6A;
+}
+pre.twilight .Keyword {
+ color: #CDA869;
+}
+pre.twilight {
+ background-color: #141414;
+ color: #F8F8F8;
+}
+pre.twilight .CssPropertyName {
+ color: #C5AF75;
+}
+pre.twilight .DoctypeXmlProcessing {
+ color: #494949;
+}
+pre.twilight .InvalidDeprecated {
+ color: #D2A8A1;
+ font-style: italic;
+}
+pre.twilight .Variable {
+ color: #7587A6;
+}
+pre.twilight .Entity {
+ color: #9B703F;
+}
+pre.twilight .Comment {
+ color: #5F5A60;
+ font-style: italic;
+}
+
90 content/css/style.css
@@ -0,0 +1,90 @@
+body {
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ margin: 0;
+}
+
+a {
+ text-decoration: none;
+ color: #3471CD;
+}
+
+a:hover {
+ text-decoration: underline;
+ color: #3471CD;
+}
+
+hr {
+ size: 100%;
+ border-top: 1px dotted #999;
+}
+
+p {
+ font-size: 14px;
+}
+
+h1 {
+ font-size: 30px;
+ color: #6686BD;
+}
+
+h2 {
+ font-size: 18px;
+ color: black;
+}
+
+h3 {
+ font-size:14px;
+}
+
+h4 {
+ font-size:14px;
+}
+
+body code {
+ color: #444;
+ font-size: 120%;
+}
+
+body pre {
+ padding: 1em;
+ border: 1px solid #dfe2e5;
+ overflow-x: auto;
+}
+
+.header {
+ padding-top: 20px;
+ padding-left: 100px;
+ top: 0px;
+ height: 120px;
+ background-color: #3F2916;
+ border-bottom:2px solid #999;
+}
+
+.wrapper {
+ width: 900px;
+ margin-top:40px;
+ margin-bottom:100px;
+}
+
+.main {
+ float:left;
+ padding-left: 100px;
+ width: 750px;
+}
+
+.credit {
+ font-style: italic;
+}
+
+.index li {
+ list-style-image: url("/img/icon1.png");
+ list-style-type: square;
+}
+
+.footer {
+ font-size: 13px;
+ clear: both;
+ padding: 25px 0 30px 100px;
+ border-top: 2px solid #999;
+ height: 40px;
+}
BIN content/img/cookbook.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN content/img/logo-mongodb-home.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 content/index.txt
@@ -0,0 +1,20 @@
+---
+title: MongoDB Recipes
+created_at: 2008-08-02 14:06:40.000000 -06:00
+dirty: true
+filter:
+ - erb
+ - textile
+---
+<h1>Recipes</h1>
+
+<% ['patterns', 'operations'].each do |subject| %>
+ <% articles = @pages.find(:all, :in_directory => subject, :recursive => true, :recipe => true) %>
+ <h2><%= subject.capitalize %></h2>
+ <ul>
+ <% articles.each do |article| %>
+ <li><%= link_to_page(article) %></li>
+ <% end %>
+ </ul>
+
+<% end %>
34 content/operations/recipe.txt
@@ -0,0 +1,34 @@
+---
+title: Sample Ops Recipe
+created_at: 2010-04-19 10:05:24.036546 -04:00
+recipe: true
+author: Kyle Banker
+description: The first ops recipe.
+filter:
+ - erb
+ - markdown
+---
+
+### Problem
+
+You want to be able to:
+
+* List objectives here
+
+### Solution
+
+#### 1. Step 1
+
+Here's a sample code block.
+<% code 'javascript' do %>
+db.foo.find();
+db.foo.hello();
+<% end %>
+
+#### 2. Step 2
+
+### Discussion
+
+Any relevant notes.
+
+### See Also
90 content/patterns/votes.txt
@@ -0,0 +1,90 @@
+---
+title: Voting with Atomic Operators
+created_at: 2010-04-19 10:05:24.036546 -04:00
+recipe: true
+author: Kyle Banker
+description: How to use MongoDB atomic operators to implement efficient voting.
+filter:
+ - erb
+ - markdown
+---
+
+### Problem
+
+You want to give your users the ability to vote on things. Whether it's articles,
+comments, photos, or tweets, it seems like everything needs voteability.
+
+* Make sure that each user gets just one vote.
+* Keep a counter cache on the number of votes.
+
+### Solution
+
+The solution is provided in JavaScript; translating to the language of your choice
+should be pretty straightforward.
+
+#### 1. Store the vote information in the object itself.
+
+Let's say you're building a social news site like Digg. You want your users to be able
+to vote on submitted stories. Here's a sample story document with all the information
+required for voting:
+
+Here's a sample code block.
+<% code 'javascript' do %>
+{'_id': ObjectId("4bcc9e697e020f2d44471d27"),
+ title: 'Aliens discovered on Mars!',
+ description: 'Martian'
+ vote_count: 0,
+ voters: []
+}
+<% end %>
+
+Notice that we've reserved two fields for voting: the first is an integer caching the number of votes,
+and the second is a list of voters.
+
+#### 2. Use an atomic update operation for adding and removing votes.
+
+Here you get to see what's great about atomic operators. You can reliably add the vote, without
+risking a duplicate, in a single operation. Here's the code to update the story above:
+
+<% code 'javascript' do %>
+// Get the user id who's voting
+user_id = ObjectId("4bcc9e697e020f2d44471a15");
+
+// This query succeeds only if the voters array doesn't contain the user
+query = {_id: ObjectId("4bcc9e697e020f2d44471d27"), voters: {'$ne': user_id});
+
+// Update to add the user to the array and increment the number of votes.
+update = {'$push': {'voters': user_id}, '$inc': {vote_count: 1}}
+
+db.stories.update(query, update);
+<% end %>
+
+#### 3. If you want to allow users to retract their votes, the code is quite simiar:
+
+The only difference is that we use the **$pull** operator, and we decrement by passing
+-1 to **$inc**.
+
+<% code 'javascript' do %>
+// This query succeeds when the voter has already voted on the story.
+query = {_id: ObjectId("4bcc9e697e020f2d44471d27"), voters: user_id};
+
+// Update to remove the user from the array and decrement the number of votes.
+update = {'$pull': {'voters': user_id}, '$inc': {vote_count: -1}}
+
+db.stories.update(query, update);
+<% end %>
+
+### Discussion
+
+One thing to note is that because the operation of step 2 uses the **$ne** operator, that part of the query
+can't use an index. This may become a problem if you expect many hundreds of votes per story; any fewer
+shouldn't be a concern.
+
+By contrast, the query in step 3 _can_ use a compound index efficiently:
+
+<% code 'javascript' do %>
+db.stories.ensureIndex({'_id': 1, voters: 1})l
+<% end %>
+
+However, you'd create this index only if you expect people to be changing their votes often (which probably
+isn't the case).
44 layouts/default.txt
@@ -0,0 +1,44 @@
+---
+extension: html
+filter: erb
+description: MongoDB Recipes.
+---
+<html>
+<head>
+ <% if @page.recipe %>
+ <title><%= @page.title %> | The MongoDB Cookbook</title>
+ <% else %>
+ <title>The MongoDB Cookbook</title>
+ <% end %>
+ <link rel="stylesheet" href="/css/style.css" />
+ <link rel="stylesheet" href="/css/code.css" />
+
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta name="description" content="<%= @page.description || 'Standard' %>" />
+</head>
+<body>
+
+<a href="http://github.com/you"><img style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png" alt="Fork me on GitHub" /></a>
+
+<div class='header'>
+ <h1><a href='/'><img src="/img/logo-mongodb-home.png" border="0" alt="MongoDB Cookbook"></a>
+ <a href='/'><img src="/img/cookbook.png" border="0" alt="MongoDB Cookbook"></a></h1>
+</div>
+
+<div class='main'>
+ <% if @page.recipe %>
+ <h1><%= @page.title %></h1>
+
+ <div class='credit'>
+ Credit: <%= @page.author %>
+ </div>
+ <% end %>
+ <%= @content %>
+</div>
+
+<div class='footer'>
+ Edited by <a href='http://mongodb.org'>The MongoDB Folks</a>. License: <a href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution Share Alike 3.0</a>. Inspired by <a href="http://rediscookbook.org/">The Redis Cookbook</a>.
+</div>
+
+</body>
+</html>
7 lib/helpers.rb
@@ -0,0 +1,7 @@
+module Helpers
+ def code(lang, &block)
+ uv(:lang => lang, :theme => "twilight", &block)
+ end
+end
+
+Webby::Helpers.register(Helpers)
31 lib/webby/page.rb
@@ -0,0 +1,31 @@
+# Monkey patch Webby to have nicer URLs.
+# Generate each html pages in a <page_name>/index.html file.
+# So the URL will look like /<page_name>
+# Credits to Marc-André Cournoyer.
+module Webby::Resources
+ class Page < Resource
+ def destination
+ dest = super
+ if prettify?
+ File.join(File.dirname(dest),
+ File.basename(dest, ".*"),
+ "index.html")
+ else
+ dest
+ end
+ end
+
+ def url
+ if prettify?
+ super.gsub(/index\.html$/, "")
+ else
+ super
+ end
+ end
+
+ private
+ def prettify?
+ filename != "index" && extension == "html"
+ end
+ end
+end
10 templates/_partial.erb
@@ -0,0 +1,10 @@
+---
+filter: erb
+---
+A partial has access to the page from which it was called. The title below will be the title of the page in which this partial is rendered.
+
+<%%= h(@page.title) %>
+
+A partial does not have access to it's own meta-data. The partial meta-data is used primarily for finding partials or for use in other pages. The filter(s) specified in the meta-data will be applied to the partial text when it is rendered.
+
+A partial does not require meta-data at all. They can contain just text.
18 templates/page.erb
@@ -0,0 +1,18 @@
+---
+title: <%= title %>
+created_at: <%= Time.now.to_y %>
+filter:
+ - erb
+ - textile
+---
+p(title). <%%= h(@page.title) %>
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc congue ipsum vestibulum libero. Aenean vitae justo. Nam eget tellus. Etiam convallis, est eu lobortis mattis, lectus tellus tempus felis, a ultricies erat ipsum at metus.
+
+h2. Litora Sociis
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et risus. Aliquam nisl. Nulla facilisi. Cras accumsan vestibulum ante. Vestibulum sed tortor. Praesent tempus fringilla elit. Ut elit diam, sagittis in, nonummy in, gravida non, nunc. Ut orci. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nam egestas, orci eu imperdiet malesuada, nisl purus fringilla odio, quis commodo est orci vitae justo. Aliquam placerat odio tincidunt nulla. Cras in libero. Aenean rutrum, magna non tristique posuere, erat odio eleifend nisl, non convallis est tortor blandit ligula. Nulla id augue.
+
+bq. Nullam mattis, odio ut tempus facilisis, metus nisl facilisis metus, auctor consectetuer felis ligula nec mauris. Vestibulum odio erat, fermentum at, commodo vitae, ultrices et, urna. Mauris vulputate, mi pulvinar sagittis condimentum, sem nulla aliquam velit, sed imperdiet mi purus eu magna. Nulla varius metus ut eros. Aenean aliquet magna eget orci. Class aptent taciti sociosqu ad litora.
+
+Vivamus euismod. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse vel nibh ut turpis dictum sagittis. Aliquam vel velit a elit auctor sollicitudin. Nam vel dui vel neque lacinia pretium. Quisque nunc erat, venenatis id, volutpat ut, scelerisque sed, diam. Mauris ante. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec mattis. Morbi dignissim sollicitudin libero. Nulla lorem.

0 comments on commit 73a288b

Please sign in to comment.
Something went wrong with that request. Please try again.