Quick-and-dirty unique constraints in Raven DB

Raven DB, like most NoSQL databases designed to be fast and scale out, does not readily support enforcing uniqueness of fields between documents. If two users must not share the same email address or Facebook ID, you cannot simply add a unique constraint for it.

However, Raven DB does guarantee uniqueness in one place: each document must have a unique ID, or a ConcurrencyException will be thrown. By creating dummy documents with say, an email address for an ID, this feature can be effectively exploited to achieve unique constraints in Raven DB.

You can easily add this behaviour to your database if you install the Raven DB UniqueConstraints Bundle, which will enforce uniqueness on updates as well as inserts. However… if the field is immutable and you just want something quick and dirty you can use this: RavenUniqueInserter.cs :)

using (var session = documentStore.OpenSession())
    var user = new User
                       EmailAddress = "rdingwall@gmail.com",
                       Name = "Richard Dingwall"
        new RavenUniqueInserter()
            .StoreUnique(session, user, p => p.EmailAddress);
    catch (ConcurrencyException)
        // email address already in use

It works by simply wrapping the call to DocumentSession.Store() with another document – in this case, it would also create a document with ID UniqueConstraints/MyApp.User/rdingwall@gmail.com, guaranteed to be unique.

You can grab it here: https://gist.github.com/1950991

5 thoughts on “Quick-and-dirty unique constraints in Raven DB

  1. I understand that this is a Insert(Create) operation, don’t you think that it’s a little misleading that a Concurrency Exception when a UniqueConstraintException DuplicateKeyException should be thrown.

    How will we handle a use case when its really a Concurrency Exception on the original entity? Let say someone change the email address after a load and updating the document- not a uniqueness issue but really an concurrency issue. I guess we might need to modify our exception handling to be more explicit to understand which document is causing the concurrency exception and that might give us a clue.


  2. Juma: good questions. I think you can interrogate the ConcurrencyException to find out more details that you could use to work around this. But it’s still quick and dirty !

Leave a Reply