Archive

Archive for December, 2011

RavenDB – Map Reduce

December 22nd, 2011 2 comments

So, learning Map Reduce in RavenDB I decided that to take what I learnt from the index created in my previous post. I think I picked something rather difficult to begin with, but I’ve succeeded Smile

Given a document Article which has a collection of Tags.

I want to get a Count of each Tag across all Articles.

public class Content
{
    public int Id { get; set; }
    public string Title { get; set; }

    public IEnumerable<Tag> Tags { get; set; }
}

public class Tag
{
    public string Name { get; set; }
}

Note: Tag is it’s own class because I added additional properties to it.

Now I insert some data:

using (var session = documentStore.OpenSession())
{
    session.Store(new Content
    {
        Title = "Test Title for a Video",
        Tags = new List<Tag>
        {
            new Tag() {Name = "c#"},
            new Tag() {Name = "autofac"},
            new Tag() {Name = "asp.net"},
        }
    });
    session.Store(new Content
    {
        Title = "Test Title for an Article",
        Tags = new List<Tag>
        {
            new Tag() {Name = "c#"},
            new Tag() {Name = "nhibernate"},
            new Tag() {Name = "fluent-nhibernate"},
            new Tag() {Name = "mvc"}
        }
    });
    session.Store(new Content
    {
        Title = "Test Title for an Article",
        Tags = new List<Tag>
        {
            new Tag() {Name = "ravendb"},
            new Tag() {Name = "asp.net"},
            new Tag() {Name = "autofac"},
            new Tag() {Name = "c#"}
        }
    });

    session.SaveChanges();
}

 

So I’m expecting a count of:

  • 3 x c#
  • 2 x autofac
  • 2 x asp.net
  • 1 x ravendb
  • 1 x mvc
  • 1 x nhibernate
  • 1 x fluent-nhibernate
  • I’m going to pull these out with a defined type rather than dynamic/object, so I’ve created a new class with Count and Name:

    public class TagResult
    {
        public int      Count   { get; set; }
        public string   Name    { get; set; }
    }

So creating a new Index:

public class All_Tags : AbstractMultiMapIndexCreationTask<TagResult>
{
    public All_Tags()
    {
    }
}

The first thing I need to do is map out ONLY the Tag’s, when I select out the Tag’s, I’m also going to include another field called Count, with a default value of 1. This is so I can re-use it to sum the total number of times the tag is used.

AddMap<Content>(contents => from content in contents
                            from tag in content.Tags
                            select new
                            {
                                Name = tag.Name,
                                Count = 1
                            });

This would give me a result that contains duplicates for the tags. Along the lines of:

c# 1
c# 1
c# 1
autofac 1
autofac 1
asp.net 1
asp.net 1
ravendb 1
mvc 1
nhibernate 1
fluent-nhibernate 1

So what I need to do in the Reduce, is group the tags together by their Name.

Reduce = results => from result in results
                    group result by result.Name into tag
                    select new
                    {
                        Count = tag.Sum(x => x.Count),
                        Name = tag.Key,
                    };

So here, I group all the tags together by their name, but I also sum the ‘count’ value together to get the total number of times the tag is used.

Now run up the app and view the index:

image

Now if I query the index:

image

Awesome. Now to query this, I have to use the TagResult class defined previously, and the All_Tags index just created.

using (var session = documentStore.OpenSession())
{
    var result = session.Query<TagResult, All_Tags>()
                        .ToList();

    foreach (var tag in result)
    {
        Console.WriteLine(tag.Count + " x " + tag.Name);
    }

    session.SaveChanges();
}

Running this I get the following result:

image

The results I expected previously.

So there you have it. Map Reduce.

Categories: RavenDB Tags:

RavenDB Inheritance–Revisited

December 14th, 2011 4 comments

So after my initial post on RavenDB Inheritance, and the issue I had with polymorphic queries, and seeking help from the guys in JabbR and the RavenDB Google Group, Ayende ended up doing a screen cast with me where he solved all my problems.

One of the things he asked me was what I was trying to achieve by having a polymorphic query, which was a very good question, something I hadn’t really thought about.

The problem I was trying to solve was actually displaying search results.

The Problem

So I’m working on a personal project, and I need to display a few things which are similar, but different. There’s 3 different types but I’ll use two to keep it simple. I’ve also cut out most of the properties.

So I have an abstract class Content, with two derived classes, Article and Video.

public abstract class Content
{
    public int Id { get; set; }
    public string Title { get; set; }
    public DateTime DatePublished { get; set; }
}

public class Article : Content
{
    public string HtmlContent { get; set; }
}

public class Video : Content
{
    public string Description { get; set; }
    public string VideoUrl { get; set; }
}

Then I initialize the DocumentStore and store a couple of documents.

var documentStore =
    (new DocumentStore()
            {
                Url = "http://localhost:8080"
            }).Initialize();

using (var session = documentStore.OpenSession())
{
    session.Store(new Video
    {
        DatePublished = DateTime.Now,
        Description = "Test Description for a Video",
        Title = "Test Title for a Video",
        VideoUrl = "http://www.youtube.com/watch?v=PGz9GokDkkg"
    });

    session.Store(new Article
    {
        DatePublished = DateTime.Now,
        Title = "Test Title for an Article",
        HtmlContent = "Some content for the article…"
    });

    session.SaveChanges();
}

This time I’m not using the Convention to store the two documents as ‘Content’, rather I’m allowing it to store them as what they are. This gives me a result in Raven like:

image

Now if I query for Video:

using (var session = documentStore.OpenSession())
{
    var result = session.Query<Video>().ToList();
    
    foreach (var content in result)
    {
        Console.WriteLine(content.Id);
        Console.WriteLine(content.Title);
    }
}

I get the output of the first Document.

image

Likewise if I select ‘Article’ I get the Article document that I previously stored.

So how do I get a list of Content?

The Solution

So, the solution is really, really easy, it’s an index.

The first thing Ayende showed me was creating the index in RavenDB Management Studio, then he showed me doing it in code. I’m just going to show it done in code.

I created a class called ‘All_Content’ (with an underscore) like so:

public class All_Content : AbstractMultiMapIndexCreationTask
{
    public All_Content()
    {
        AddMap<Article>(articles => from article in articles
                                    select new
                                                {
                                                    article.Id,
                                                    article.Title,
                                                    article.DatePublished
                                                });
        AddMap<Video>(videos => from video in videos
                                select new
                                            {
                                                video.Id,
                                                video.Title,
                                                video.DatePublished
                                            });
    }
}

It reminds me of writing a Union View in SQL Server in some ways. It basically maps to the Articles and Videos, but only selects the things I need. Those of which would actually be displayed to the screen or that are common between the two document types.

Then I create the index right after I initialize the DocumentStore:

IndexCreation.CreateIndexes(typeof(All_Content).Assembly, documentStore);

This creates the index in RavenDB for me.

image

As you can see, even tho I specified the class index with an underscore, it converts it to All/Content, that’s a really nice way of presenting it. I think it will go well for being able to create descriptive indexes in the future.

And the index itself:

image

Now I need to actually query against the index. That’s also really really easy. When I specify the type, I can specify the index with it:

using (var session = documentStore.OpenSession())
{
    var result = session.Query<Content, All_Content>().ToList();
    
    foreach (var content in result)
    {
        Console.WriteLine(content.Id);
        Console.WriteLine(content.Title);
    }
}

Now when I run this I get the output:

image

Awesome!

The really interesting thing I found is that if I look at what’s returned:

image

Are the correct CLR types that I originally defined. So I haven’t lost all the additional fields by not defining them. I’m still learning but for now I assume it allows those fields to be searchable.

Extras

One of the additional things Ayende showed me was that you can include other documents that don’t inherit from the base type. You can include those in the index map, and then rather than returning a concrete type, you can specify object, or dynamic.

var result = session.Query<dynamic, All_Content>().ToList();

RavenDB is really powerful. It’s truly amazing, and so much nicer to work with in .NET than other document databases like MongoDB.

Categories: RavenDB Tags:

RavenDB Inheritance

December 10th, 2011 1 comment

Edit: Updated solution: http://www.philliphaydon.com/2011/12/ravendb-inheritance-revisited/

Continuing my learning of RavenDB, I wanted to see how it handled Inheritance.

I found: http://ravendb.net/faq/polymorphic-indexes

Which showed what to do allow you to select over all types of ‘Animal’ for the example shown. So I wanted to see what happens before and after using this method.

So like the example shown I’ve created an Animal, with a Dog and Cat.

public abstract class Animal
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Dog : Animal { }
public class Cat : Animal { }

Now if I insert a Dog and Cat:

using (var session = documentStore.OpenSession())
{
    session.Store(new Dog() { Name = "Test Dog" });
    session.Store(new Cat() { Name = "Test Cat" });

    session.SaveChanges();
}

What’s stored in RavenDB is two separate documents, one for ‘dogs’ and one for ‘cats’.

image

If I include the Convention.

var documentConvention =
    new DocumentConvention()
        {
            FindTypeTagName =
                type =>
                    {
                        if (typeof (Animal).IsAssignableFrom(type))
                            return "animals";
                        return DocumentConvention.DefaultTypeTagName(type);
                    }
        };

Note: You can do the conversion when the DocumentStore is initialized, I broke the two up so that it would fit easier into my blog. Otherwise it’s too nested and yucky.

var documentStore =
    (new DocumentStore()
            {
                Url = "http://localhost:8080",
                Conventions = documentConvention
            }).Initialize();

Now when I insert a Dog and Cat I get:

image

Awesome. If we look at the document however:

image

There is no information about it being a cat or dog, I thought it would add some sort of discriminator similar to how NHibernate works.

However, if we look at the Metadata tab:

image

We can see the CLR type is stored in the metadata so RavenDB knows what type to create when we query it.

This means if we query for ‘Animal’ we get a list of Dogs and Cats.

using (var session = documentStore.OpenSession())
{
    var result = session.Query<Animal>();

    foreach (var animal in result)
    {
        Console.WriteLine(animal.Name);
    }
}

 

image

However, if you wanted to query for just Dogs, like so:

var result = session.Query<Dog>().ToList();

It doesn’t seem to work Sad smile

image

I’m probably just doing something wrong, either way, the more I play with RavenDB. The more I love it.

Categories: RavenDB Tags:

Post a collection of ViewModel’s to a MVC Action with jQuery

December 7th, 2011 No comments

Maybe I searched for the wrong thing, but I couldn’t find what I was looking for Sad smile My Bing and Google fu failed me.

Basically I wanted to post a collection of ViewModels to an MCV action. Turns out it’s rather simple.

Lets say I have a bunch of Products, and Products are managed in a WarehouseLocation. A product doesn’t have a warehouse location, since it could exist in multiple locations.

If I’m currently working in Location A, I want to post a collection of Products to an action, as well as the WarehouseLocationId.

So given a simple ViewModel, and an Action:

public class ProductViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

and

public JsonResult Update(int warehouseLocationId, IEnumerable<ProductViewModel> products)
{
    //Do something with the products…

    return Json(new {Staus = "success"});
}

I think usually when someone sends data from jQuery it’s usually a single parameter,so the JSON would look something like:

var data = { id: 1,name: ‘test name’, price: 15.95 };

This would populate an action that looked like:

public JsonResult Update(ProductViewModel product)

But what I was faced with was passing in two parameters, one of which is a collection…

MVC seems to pair up the posted result with the parameter name, in the same way they it does for Route parameters. So to the JSON needs to look like:

var data = {
    warehouseLocationId: 12,
    products: [{
        Id: 1,
        Name: "Product 1",
        Price: 15.95
    }, {
        Id: 3,
        Name: "Product 2",
        Price: 12.50
    }]
};

As you can see the key’s on the first level match the parameter names, while the array on products, match the ViewModel.

Taking this exact data and posting it to the action:

$.ajax({
        type: 'POST',
        url: '@Url.Action("Update", "Home")',
        data: JSON.stringify(data),
        contentType: 'application/json',
        success: function(result) {
            //Do something with result…
        },
        dataType: 'json'
    });

 

I submit that, and with a breakpoint on my action I see:

image

^ The warehouseLocationId…

image

^ 2 products with the values:

image

And:

image

The exact same data we defined in our JavaScript.

The really cool thing about this, is you can have nested collections also. Using the same scenario, but extending Product to have a collection of Categories like so:

public class ProductViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }

    public IEnumerable<Category> Categories { get; set; }
}

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
}

I can update the JSON object to include Category information on 1 of the two products:

var data = {
    warehouseLocationId: 12,
    products: [{
        Id: 1,
        Name: "Product 1",
        Price: 15.95
    }, {
        Id: 3,
        Name: "Product 2",
        Price: 12.50,
        Categories: [{
            Id: 1,
            Name: "Category 1"
        }, {
            Id: 1,
            Name: "Category 2"
        }]
    }]
};

And submit that in the same way as before, capturing the results in the Action we get the first product with null for the categories, since we didn’t define it as an empty array:

image

While the second Product has 2 items, the first item is Category 1, and the second item is Category 2.

image

image

And that’s it, easy peasy, sending a collection of ViewModels from jQuery to an MVC Action.

I <3 MVC Smile

Categories: MVC, jQuery Tags: , ,