RavenDB

  • RavenDB Survival Tip #3: Handling Polymorphism

    If you want to store objects in your database that are implementations of interfaces or base classes, you can do this pretty easily by alternating Raven’s JSON serializer settings so that when Raven serializes your object, it includes a special “$type” property in the JSON that records the full type name of the object.

    The documentation for RavenDB actually mentions this, but there’s a little change that I do to make it a little more efficient.  The docs say to use a TypeNameHandling convention of “All” but this will emit the $type property on every single object.  This is a waste of space and creates a lot of clutter.  You should instead use TypeNameHandling.Auto.  This setting will only include the $type property if the type of the property does not match the actual type of the object. 

    Here’s how you’d set this up (I’m assuming that you have a DocumentStore instance available).  You’d perform this setup only when initially creating the DocumentStore (once per app):

    store.Conventions.CustomizeJsonSerializer = serializer =>
    {
        serializer.TypeNameHandling = 
            Raven.Imports.Newtonsoft.Json.TypeNameHandling.Auto;
    };
    

    Categories: RavenDB

  • RavenDB Survival Tip #2: Simulating select count(*)

    A lot of the time a user will ask for a count of some business entity on a report so they can tell how many of something is happening.  With SQL, this is a very natural process with aggregate operations:

    select count(*) from Users where IsAdmin = true
    

     

    But with RavenDB, I found it difficult to wrap my mind around how you would do this with an Index.  Aggregate operations like this are implemented with map/reduce indexes.  Since the reduce step of the index needs to have the same output shape as the map, we can’t simply return a single numeric value as is the case with SELECT COUNT(*) in SQL.  We need to perform a LINQ group-by.  But in this case, I don’t really want to group by anything in a document, I just want a count. 

    After a little thinking and digging around, I found a solution.  Maybe this is obvious to most, but I found that if we simply group by a constant, we can get a single numeric value for that constant the represents the total count.

    Here’s a sample Index definition that demonstrates this concept.  In the Index, I am trying to find all User documents that qualify as admins (IsAdmin = true).

    public class Users_AdminCounts : AbstractIndexCreationTask<User, Users_AdminCounts.ReduceResult>
    {
        public class ReduceResult
        {
            public string Name { get; set; }
            public int Count { get; set; }
        }
    
        public Users_AdminCounts()
        {
            // the Name parameter to the reduce function is dummy
            // to get it to aggregate to one single value
            Map = users =>
                from user in users
                where user.IsAdmin = true
                select new { Name = "Total", Count = 1 };
    
            Reduce = results =>
                from result in results
                group result by result.Name
                into g
                select new { Name = g.Key, Count = g.Sum(x => x.Count) };
        }
    }
    

     

    When you run the query and get the result (ReduceResult), you will get just one single result and the Count property will contain the count aggregate you are looking for.

    Categories: RavenDB

    Tags: RavenDB, SQL

  • RavenDB Survival Tip #1: Indexing Gotcha

    This series of posts is going to cover some things I’ve learned using RavenDB, a document database solution for .NET. 

    I was working on a class (a User class) where I needed to add a property to the class that didn’t exist in the original version of the application.   So, I went and added it to the C# class (User) and I also updated an Index in RavenDB to use this new property so that I could filter by it in a query.  It built and when I deployed I could see that Raven was updating the index and did so in a timely manner.

    I then went and wrote some code to filter by that new property in a query.  The property I had added was a boolean type and so all of the models that I had in the database (some 50,000+ User documents) would just get the default value of false for this new property.   However, when I went to run this query, no documents were returned.  What happened was that when you add a new property to a model, it isn’t going to go and update all of your existing documents with a property value even if a default is implied or provided (as is the case with a bool being false by default).  There is simply no property in the JSON store in the User document that matches this property I was querying by. 

    The solution is that when you do something like that, you need to run a Patch in RavenDB.  This will ensure that all of your documents get synced to the new additional property you have made.  Perhaps if this was some integer or string property that had to be set to something specific I would have picked up on the problem before even attempting the query. 

    Categories: RavenDB

  • Setting Up RavenDB as IIS Website

    Over the past year, I’ve gotten to know RavenDB which is an excellent NoSQL document database product from Hibernating Rhinos.  It’s an open source project built in .NET that fits in well with .NET technologies like LINQ.  I love the process of taking my domain objects and simply dumping them into a database and being able to retrieve them with very little effort.  The programming experience is excellent.

    But since this is new to most people (and organizations), getting started setting up a RavenDB server to connect to can be a little challenging getting everything right, especially if you don’t have the infrastructure support of IIS experts and/or DBAs.  This post shows step-by-step instructions on how to set up RavenDB on an IIS 7.x system.  These instructions have worked well for me and make the following assumptions:

    • You want to use IIS to host RavenDB (you can also embed it or use Windows Services – I won’t talk about that right now).
    • You want to use HTTPS as your transport protocol.
    • You want to use integrated Windows security to authorize users to access your DB.

    Here’s what you should do to achieve this (this is for version 2.0 of RavenDB, build 2261 or higher):

    1. Ensure you have the following software installed on your server:
      1. IIS 7.5
      2. .NET Framework 4.0 – it might not be installed if you are on Windows Server 2008 (it shipped with 3.5 SP1)
      3. Get the .zip of the latest stable RavenDB build (or an unstable build if you wish).  Unzip to a directory on the server.  The sub-directory /Web is where the web site will run from.  I put this on same disk as the Raven Data directory.
    2. Install Windows Authentication service.
      1. Server Manager –> Roles –> Web Server, then click on Add Role Services link.
      2. Check “Windows Authentication” and then continue.
    3. Setup proper DNS to point to your server’s IP address (this is probably already done).
    4. If you are behind a corporate firewall, have them open port 8080 (or whatever port you are using).  You probably want it open to your entire subnet including a VPN IP range if you have that.
    5. Obtain and install an SSL certificate for the domain for the machine.
    6. Create a new application pool for the web site.
      1. Set it to use .NET 4.0 and Integrated Pipeline.
      2. Give it a name such as “RavenAppPool”
    7. Disable overlapped recycle on the app pool.  Raven doesn’t want multiple instances attempting to write to its files.
      1. On the app pool you just created –> Advanced Settings –> Disable Overlapped Recycle set to True.
    8. Set the app pool so that IIS never shuts it down.  You want your DB up at all times.
      1. The setting for this can’t be applied in the GUI for IIS 7.5.
      2. Find C:\Windows\System32\inetsrv\config\applicationHost.config and open it.  Make a backup copy.
      3. Find the app pool entry for the app pool you created for Raven.
      4. Add the attribute startMode=”AlwaysRunning” to it and save the file.
    9. Create a new website or set Default Web Site.
      1. Right click Sites under Web Server and choose Add New Site.
      2. Set site name to “RavenDB” or whatever you want.
      3. Set the app pool to the RavenAppPool you created in step 6.
      4. Set the physical path to the /Web folder of the RavenDB install.
      5. Set HTTP binding if not already.
      6. Uncheck start web site immediately.
      7. Click OK.
    10. Create a RavenDB user group.  This is a Windows group that represents the users that can login to RavenDB.
      1. Server Manager –> Configuration –> Local Users and Groups…
      2. Right-click on Groups folder, select New Group…
      3. Give group a name and description ("RavenDB”)
      4. Click OK.
    11. If you are connecting with an application, create a new user now for the proxy account that will use this database.  This user should belong to the \RavenDB group you just created.  You should also create any DBA or developer accounts now and give them this group as well.
    12. Turn on Require SSL for the website.
    13. Configure where Indexes and Data directories are.  You should have two different disks for best parallel I/O – one for the Indexes and one for the Data.
      1. Open the web.config file in the /Web folder of the RavenDB install.
      2. In <appSettings>, add a setting for data path - <add key=”Raven/DataDir” value=”[your path here]” />
      3. Also add a setting for indexes - <add key=”Raven/IndexStoragePath” value=”[your path here]” />
    14. Start the web site.
    15. In a web browser with Silverlight plugin installed, navigate to https://[yoursitedomain]:[port]/ to make sure the Management Studio opens.  If it works, you know that RavenDB started, created the default database and that your website is serving data correctly over HTTPS and your firewall rules are correct.
    16. Turn on Windows Authentication
      1. Click on RavenDB web site just created.
      2. Select Authentication from IIS categories.
      3. Click on Windows Authentication from the list and click Enable link  on the actions panel.
      4. Turn off anonymous access in Raven:  open its web.config file and add the following setting to the <appSettings> section - <add key=”Raven/AnonymousAccess” value=”None” />
    17. Configure Raven to only allow that specific Windows group you created earlier.
      1. In Raven Management studio, click on the databases link at the top right. 
      2. Click on the <system> database button on the right.  It will warn you about modifying the system database, just click OK.
      3. Now click the “gear” icon at the top next to the <system> database name to open the settings for the db.
      4. Select Windows Authentication from the left pane.
      5. On the Groups tab, click Add Group Settings.
      6. In the Name text box, add the name of your windows group preceded by a slash (“\RavenDB”).
      7. Check Enabled.
      8. Add the specific databases to the group (such as the default database or a specific tenant you may have created).
      9. Click Save Changes button to complete.
    18. Open Management Studio again.  You should be prompted by your browser for a username and password.

    These instructions will create you a running RavenDB instance in IIS that has HTTPS transport security, Windows security, and does not allow anonymous access.  It also configured where indexes and data are written to and made sure IIS doesn’t recycle your process or start two of them at once.

    The official documentation can also help you out if you are having any trouble:  http://ravendb.net/docs/2.0/server/deployment/as-iis-application

    Categories: RavenDB

  • 1