code first net and mongodb
Download
Skip this Video
Download Presentation
Code-First .NET and MongoDB

Loading in 2 Seconds...

play fullscreen
1 / 44

code-first and mongodb - PowerPoint PPT Presentation


  • 567 Views
  • Uploaded on

The Ubiquitous Blog Example Philly ALT.NET User Group 2010-11-16 John C. Zablocki Development Lead, MagazineRadar Adjunct, Fairfield University. Code-First .NET and MongoDB. Agenda. MongoDB Basic Concepts MongoDB Shell NoRM MongoDB C# Driver MongoDB Design Considerations

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'code-first and mongodb' - Mercy


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
code first net and mongodb

The Ubiquitous Blog Example

Philly ALT.NET User Group

2010-11-16

John C. Zablocki

Development Lead, MagazineRadar

Adjunct, Fairfield University

Code-First .NET and MongoDB
agenda
Agenda
  • MongoDB Basic Concepts
  • MongoDB Shell
  • NoRM
  • MongoDB C# Driver
  • MongoDB Design Considerations
  • In Depth: Meringue
  • Case Study: RateMySnippet
  • Questions?
mongodb concepts
MongoDB Concepts
  • Schema-less documents stored in collections
  • Documents are stored as BSON (Binary JSON)
  • JavaScript used to query and manipulate documents and collections
  • Each document in a collection has a unique BSON ObjectId field named _id
  • Collections belong to a database
installing mongodb on windows
Installing MongoDB on Windows
  • Download the binaries from mongodb.org
  • Extract to Program Files directory (or wherever)
  • Create a directory c:\data\db
  • Run mongod.exe from the command line with the --install switch
    • See http://bit.ly/aed1RW for some gotchas
  • To run the daemon without installing, simply run mongod.exe without arguments
  • Run mongo.exe to verify the daemon is running
a funny thing happened on the way to philadelphia
A funny thing happened

on the way to Philadelphia...

MongoDB and .NET
mongodb shell
MongoDB - Shell
  • The MongoDB interactive JavaScript shell (mongo.exe) is a command line utility for working with MongoDB servers
  • Allows for CRUD operations on collections
  • May be used for basic administration
    • Creating indexes
    • Cloning databases
  • Also useful as a test-bed while building apps
mongodb shell7
MongoDB - Shell

/*Connect to a server:port/database

(defaults are localhost:27017/test ):*/

mongo.exelocalhost:27017/AltNetGroup

//Switch database:

use CodeCamp

//View collections in a database:

showcollections

//create an index on Name field

db.Posts.ensureIndex({ Name : 1 });

//copy one database to another

db.copyDatabase("CodeCamp", "AltNetGroup")

mongodb shell8

//create a document

varpost = { Title: "On Installing MongoDB as a Service on Windows" }

//insert a document, if the collection doesn\'t exist it\'s created

db.Posts.insert(post);

//verify that the document was created

db.Posts.find();

//write a query to find a post with a valid title

varquery = { Title: { $ne: null} }

//use that query to find the post

varpost = db.Posts.findOne(query);

//this line will actually set the content after pressing enter

post.Content = "When installing MongoDB as a service on Windows..."

MongoDB - Shell
mongodb shell9

//update the content to include an author using collection update method

db.Posts.update( { Title : "On Installing MongoDB as a Service on Windows" }, { Author : "John Zablocki" } )

//check that the post was updated

db.Posts.findOne()

//where\'d my document go? updates are in place, replacing entire documents!

//need to use the $set operator to update partial documents - let\'s start over

//first remove the new document. Notice how remove takes a func as an argument.

//find and findOne also accept functions as arguments

db.Posts.remove(function (e) { returnthis.Author == "John Zablocki" })

//rerun the first statements up to but not including the db.Posts.update(...

db.Posts.update({ Title: "On Installing MongoDB as a Service on Windows" },

{ $set: { Author: "John Zablocki" } })

//verify that the update worked

db.Posts.findOne()

MongoDB - Shell
mongodb shell10

//add a tag to the post

db.Posts.update({ Title: "On Installing MongoDB as a Service on Windows" },

{ $push: { Tags: "mongodb" } })

//look for that tag

db.Posts.findOne()

//add two more tags

db.Posts.update({ Title: "On Installing MongoDB as a Service on Windows" },

{ $pushAll: { Tags: ["windows", "nosql"] } })

//add another post

db.Posts.insert( { Author : "John Zablocki", Title : "On MapReduce in MongoDB",

Tags: ["mongodb", "nosql"]

})

//verify that last insert worked

db.Posts.findOne(function (e) { returnthis.Title.indexOf("MapReduce") != -1; })

MongoDB - Shell
mongodb shell11

//add a "like" counter to the post. The booleans arguments tell update

//not to insert if the document doesn\'t exist and to update all documents,

//not just one respectively

db.Posts.update({ Author: "John Zablocki" }, { $set: { Likes: 0} }, false, true)

//increment the likes counter for the mapreduce article

db.Posts.update({ Title: /mapreduce/i }, { $inc: { Likes: 1} })

//check that the counter was incremented

db.Posts.findOne({ Title: /mapreduce/i }).Likes

MongoDB - Shell
mongodb shell12
MongoDB – Shell

/*

Create the map function

This function creates a view that looks like{ “mvc”, [1, 1] },

{ “norm”, [1] }*/

varmap = function() {

if (!this.Tags) { return; }

for (varindexinthis.Tags) {

emit(this.Tags[index], 1);

}

};

mongodb shell mapreduce
MongoDB – Shell MapReduce

/*

Create the reduce function

conceptually, reduce gets called like:

reduce("mvc", [1, 1]);

reduce("norm", [1]

/*

varreduce = function(key, vals) {

varcount = 0;

for (varindexinvals) {

count += vals[index];

}

returncount;

};

mongodb shell mapreduce14
MongoDB – Shell MapReduce

/*

Run the mapreduce command on the Posts collection

using the map and reduce functions defined above

store the results in a collection named Tags

*/

varresult = db.runCommand(

{

mapreduce : "Posts",

map : map,

reduce : reduce,

out : "Tags"

});

db.Tags.find()

slide17
NoRM
  • Developed by Andrew Theken among others
  • Active community with reliable support
    • I received help even as I prepared this slide!
  • Support for typed and untyped collections, MapReduce, Property Mapping, LINQ, Expando, nearly all CRUD operations
  • Will eventually sit on top of the 10gen officially supported driver
norm the basics
NoRM – The Basics

//Connections managed with IDisposable pattern

//Connect to test database on localhost

using (IMongomongo=Mongo.Create("mongodb://localhost/test")) {

Console.WriteLine(mongo.Database.DatabaseName);

}

//Mongo instance has MongoDatabase property

/*MongoDatabase has GetCollection<T> methods for accessing MongoCollection instances*/

//CRUD operations performed on collections

norm crud
NoRM - CRUD

//Class properties map to document structure

publicclassArtist {

//ObjectId property mapped to _id field in document

publicObjectIdId { get; set; }

publicstringName { get; set; }

//IList property will be mapped to JavaScript Array

privateIList<string>_albums=newList<string>(0);

publicIList<string>Albums {

get { return_albums ; }

set { _albums =value; }

}

}

norm crud20
NoRM - CRUD

varartist=newArtist() { Name="The Decembrists" };

//Inserting a document into a typed collectionmongo.Database.GetCollection<Artist>("Artists").Insert(artist);

//Updating (replacing) a document in a typed collection

artist.Name="The Decemberists"; mongo.Database.GetCollection<Artist>("Artists").Save(artist);

//Updating a nested collection

mongo.Database.GetCollection<Artist>("Artists").UpdateOne(

new { Name="The Decemberists"}, new { Albums=M.Push("Picaresque") }

);

norm crud21
NoRM - CRUD

//Find all documents in a typed collection

varartists=mongo.GetCollection<Artist>("Artists").Find();

Console.WriteLine(artists.FirstOrDefault().Name);

//Query with a document spec

varartist=mongo.GetCollection<Artist>("Artists")

.FindOne( new { Name="The Decemberists" });

Console.WriteLine(artist.Albums.Count);

//Count the documents in a collection

longcount=mongo.GetCollection<Artist>("Artists").Count();

Console.WriteLine(count);

norm mapreduce
NoRM - MapReduce

//Add a Tags collection added to Artist class

privateIList<string>_tags;

publicIList<string>Tags {

get { return_tags; }

set { _tags=value; }

}

//Add some tags – use Set not PushAll, since Tags was nullmongo.Database.GetCollection<Artist>("Artists").UpdateOne(

new { Name="The Decemberists" },

new { Tags=M.Set(newList<string>() { "Alternative", "Folk Rock }) });

norm mapreduce23
NoRM - MapReduce

//Create map and reduce functons

[email protected]"function() {

if (! this.Tags ) { return; }

for (index in this.Tags) {

emit(this.Tags[index], 1); }

}";

[email protected]"function(previous, current) {

var count = 0;

for (index in current) {

count += current[index];

}

return count;

}";

norm mapreduce24
NoRM - MapReduce

//MapReduce class is responsible for calling mapreduce command

MapReducemr=mongo.Database.CreateMapReduce();

//Represents the document passed to the //db.runCommand in the shell example

MapReduceOptionsoptions=newMapReduceOptions("Artists")

{

Map=map,

Reduce=reduce,

OutputCollectionName="Tags"

};

MapReduceResponseresponse=mr.Execute(options);

varcollection=mongo.Database.GetCollection<Tag>("Tags");

Console.WriteLine(collection.Count());

norm linq
NoRM - LINQ

//LINQ provider exposed via AsQueryable method of MongoCollection

varartists=mongo.Database.GetCollection<Artist>("Artists")

.AsQueryable();

//Find items in typed collection

varartistsWithDecInName=fromainmongo.Database.GetCollection<Artist>().AsQueryable()

wherea.Name.Contains("Dec")

selecta;

Console.WriteLine("First containing Dec in name: "+artistsWithDecInName.First().Name);

norm linq26
NoRM - LINQ

//Find artists without pulling back nested collections

//Note use of Regex name search

varartistsWithoutAlbums=

fromainmongo.Database.GetCollection<Artist>().AsQueryable()

whereRegex.IsMatch(a.Name, "ber", RegexOptions.IgnoreCase)

selectnew { Name=a.Name };

Console.WriteLine(artistsWithoutAlbums.First().Name);

//Find artists with a given tag

varartistsWithFolkRockTag=mongo.Database.GetCollection<Artist>("Artists")

.AsQueryable().Where(a=>a.Tags.Any(s=>s=="Folk Rock"));

Console.WriteLine(artistsWithFolkRockTag.First().Name);

mongodb c driver
MongoDB C# Driver
  • 10gen developed and supported
  • Consists of two primary components, a BSON serializer and the MongoDB driver
  • Support for typed and untyped collections, MapReduce, and all CRUD operations
  • Currently lacking a LINQ provider
  • Released about two weeks ago as version 0.7!
mongodb c driver the basics
MongoDB C# Driver – The Basics
  • privatestaticMongoDatabase_mongoDatabase=null;
  • staticProgram() {
  • //MongoConnectioSettings used to create connection strings
  • MongoConnectionSettingssettings=newMongoConnectionSettings();
  • settings.Address=newMongoServerAddress("localhost", 27017);
  • //MongoServer manages access to MongoDatabase
  • MongoServermongoServer=newMongoServer(settings);
  • //MongoDatabase used to access MongoCollection instances
  • _mongoDatabase=mongoServer.GetDatabase("AltNet");
  • }
mongodb c driver crud
MongoDB C# Driver - CRUD
  • varartist=newArtist() { Name="The Decembrists" };
  • //Inserting a document into a typed collection_mongoDatabase.GetCollection<Artist>(COLLECTION).Insert(artist);
  • //Updating (replacing) a document in a typed collectionartist.Name="The Decemberists";
  • _mongoDatabase.GetCollection<Artist>(COLLECTION).Save(artist);
  • //Updating a nested collection_mongoDatabase.GetCollection<Artist>(COLLECTION).Update(
  • Query.EQ("Name", "The Decemberists"),newBsonDocument("$pushAll",newBsonDocument("Albums", newBsonArray() { "Castaways and Cutouts", "Picaresque", "Hazards of Love", "The Crane Wife" }))
  • );
mongodb c driver crud30
MongoDB C# Driver - CRUD
  • //Find all documents in a typed collection
  • varartists=_mongoDatabase.GetCollection<Artist>(COLLECTION).FindAll();
  • Console.WriteLine("Artist name: "+artists.FirstOrDefault().Name);
  • //Query with a document specvarartist=_mongoDatabase.GetCollection<Artist>(COLLECTION).FindOne(newBsonDocument { { "Name", "The Decemberists" } });
  • Console.WriteLine("Album count: "+artist.Albums.Count);
  • //Count the documents in a collectionlongcount=_mongoDatabase.GetCollection<Artist>(COLLECTION).Count();Console.WriteLine("Document count: "+count);
mongodb c driver crud31
MongoDB C# Driver - CRUD
  • varartists=_mongoDatabase.GetCollection<Artist>(COLLECTION);
  • //Find items in typed collection
  • varartistsStartingWithThe=artists.Find(Query.Matches("Name", newRegex("the", RegexOptions.IgnoreCase)));
  • Console.WriteLine(artistsStartingWithThe.First().Name);
  • //Find artists without pulling back nested collectionsvarartistsWithDecInTheName=artists.Find(Query.Matches("Name", "Dec")).SetFields("Name");
  • Console.WriteLine(artistsWithDecInTheName.First().Name);
  • ////Find artists with a given tag
  • varartistsWithIndieTag=artists.Find(Query.In("Tags", "Indie"));
  • Console.WriteLine( artistsWithIndieTag.First().Name);
mongodb c driver mapreduce
MongoDB C# Driver - MapReduce
  • //Add some tags
  • _mongoDatabase.GetCollection<Artist>(COLLECTION).Update(Query.EQ("Name", "The Decemberists"),newBsonDocument("$pushAll",newBsonDocument("Tags", newBsonArray() { "Folk rock", "Indie" })) );
  • varartist=newArtist() { Name="Sunny Day Real Estate",Albums=newList<string>() { "How it Feels to be Something On", "Diary" },Tags=newList<string>() { "Indie", "Emo" }};
  • _mongoDatabase.GetCollection<Artist>(COLLECTION).Save(artist);
mongodb c driver mapreduce33
MongoDB C# Driver - MapReduce
  • _mongoDatabase.GetCollection<Artist>(COLLECTION).Save(artist);
  • //Create map and reduce [email protected]"function() {...}";
  • [email protected]"function(previous, current) { ... }";
  • varresult=_mongoDatabase.GetCollection<Artist>(COLLECTION).MapReduce(map, reduce, MapReduceOptions.SetKeepTemp(true).SetOutput("Tags"));
design considerations
Design Considerations
  • Your object graph is your data model
  • Don\'t be afraid to store data redundantly
    • Your graph might be redundant
  • Not everything has to fit in 1 document
  • Don\'t be afraid to store aggregate statistics with a document.
object graph as data model
Object Graph as Data Model
  • Generally speaking, most MongoDB drivers will serialize an object graph as a single document
    • The relationships of your classes creates an implied schema!
    • Migrating this schema is not trivial if you are trying to deserialize properties that did not or no longer exist
  • Consider use cases carefully to avoid inefficiently structured documents
  • Projection queries will be your friend
redundant data is ok
Redundant Data is OK
  • Optimize documents for quick reads and writes
  • Your application layer will have to maintain referential integrity!
  • If every time you access a Post document, you need some of an Author document\'s data, store that data with Post
  • Design simple classes for this redundant data for reusability (see AuthorInfo in Meringue)
do not stuff it in 1 document
Do Not Stuff it In 1 Document
  • Nothaving formal relationships does not mean throwing away relationships
  • Consider a user and his or her logged actions
    • The user would likely have a User class/doc with properties for name, email, etc.
    • User actions are generally write heavy and read out of band.
    • Don\'t clutter user documents - create a separate collection for user actions
don t be afraid of extra data
Don\'t Be Afraid of Extra Data
  • The schema-less nature of documents makes it easy to store meta data about that document – particularly aggregate data
  • Consider a blog post with a rating feature
    • Each rating would be stored as a nested document of the post
    • Rather than compute vote totals and averages real time, simply add these properties to the document and update on writes
slide41

Final Thoughts

Eat food. Not too much. Mostly plants.

- Michael Pollan

slide42

Final Thoughts

Write Code. Not too much. Mostly C#.

- John Zablocki

the meringue stack
The Meringue Stack
  • ASP.NET MVC
    • MVCContrib
  • MongoDB
    • Mongo C# Driver
  • Spring.NET
    • Recoil
  • AutoMapper
links
Links
  • http://dllHell.net - my blog
  • http://www.CodeVoyeur.com - my code
  • http://www.linkedin.com/in/johnzablocki
  • http://twitter.com/codevoyeur
  • http://mongodb.org - Official MongoDB site
  • http://bitbucket.org/johnzablocki/meringue
  • http://bitbucket.org/johnzablocki/codevoyeur-samples
ad