Code first net and mongodb
Download
1 / 44

code-first and mongodb - PowerPoint PPT Presentation


  • 562 Views
  • Updated 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

Related searches for code-first and mongodb

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 l.jpg

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 l.jpg
Agenda

  • MongoDB Basic Concepts

  • MongoDB Shell

  • NoRM

  • MongoDB C# Driver

  • MongoDB Design Considerations

  • In Depth: Meringue

  • Case Study: RateMySnippet

  • Questions?


Mongodb concepts l.jpg
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 l.jpg
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 l.jpg

A funny thing happened

on the way to Philadelphia...

MongoDB and .NET


Mongodb shell l.jpg
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 l.jpg
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 l.jpg

//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 l.jpg

//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 l.jpg

//add a tag to the post update method

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 l.jpg

//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 l.jpg
MongoDB – Shell tell update

/*

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 l.jpg
MongoDB – Shell MapReduce tell update

/*

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 l.jpg
MongoDB – Shell MapReduce tell update

/*

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()



Slide16 l.jpg
NoRM tell update


Slide17 l.jpg
NoRM tell update

  • 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 l.jpg
NoRM – The Basics tell update

//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 l.jpg
NoRM - CRUD tell update

//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 l.jpg
NoRM - CRUD tell update

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 l.jpg
NoRM - CRUD tell update

//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 l.jpg
NoRM - MapReduce tell update

//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 l.jpg
NoRM - MapReduce tell update

//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 l.jpg
NoRM - MapReduce tell update

//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 l.jpg
NoRM - LINQ tell update

//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 l.jpg
NoRM - LINQ tell update

//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 l.jpg
MongoDB C# Driver tell update

  • 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 l.jpg
MongoDB C# Driver – The Basics tell update

  • 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 l.jpg
MongoDB C# Driver - CRUD tell update

  • 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 l.jpg
MongoDB C# Driver - CRUD tell update

  • //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 l.jpg
MongoDB C# Driver - CRUD tell update

  • 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 l.jpg
MongoDB C# Driver - MapReduce tell update

  • //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 l.jpg
MongoDB C# Driver - MapReduce tell update

  • _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"));


In depth meringue l.jpg
In Depth: Meringue tell update


Design considerations l.jpg
Design Considerations tell update

  • 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 l.jpg
Object Graph as Data Model tell update

  • 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 l.jpg
Redundant Data is OK tell update

  • 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 l.jpg
Do Not Stuff it In 1 Document tell update

  • 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 l.jpg
Don't Be Afraid of Extra Data tell update

  • 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 l.jpg

Final Thoughts tell update

Eat food. Not too much. Mostly plants.

- Michael Pollan


Slide42 l.jpg

Final Thoughts tell update

Write Code. Not too much. Mostly C#.

- John Zablocki


The meringue stack l.jpg
The Meringue Stack tell update

  • ASP.NET MVC

    • MVCContrib

  • MongoDB

    • Mongo C# Driver

  • Spring.NET

    • Recoil

  • AutoMapper


Links l.jpg
Links tell update

  • 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