Skip to content

Using Linq to query loosely typed data in MongoDB

April 22, 2013

As of version 0.5.1 Linq to Querystring now supports Mongo DB out of the box, via the linq support provided by the C# driver. But what is really cool is that with a little bit of code, we can also write Linq queries and hence perform Linq to Querystring filtering on loosely typed data!

Fork of  the MongoDb driver

When I talk about Linq queries against loosely typed data, I mean stuff like this:

var results = mongoCollection.AsQueryable().Where(o => o["Name"] == "Roysvork");

Unfortunately this is not supported by the Mongo C# linq stuff out of the box… the driver only know hows to handle indexers when dealing with arrays. There is a pull request pending to fix this issue which will hopefully be resolved very soon, but for now you can use my fork of the driver which is also available as a nuget package:

PM> Install-Package mongocsharp.linqindexers

I will try to keep this up to date with the latest source from the driver itself, but please bear in mind that although it should be sound and working, it is not official nor supported by 10gen! Hopefully it won’t be around for very long.

Serialisation info

Now for the next step… the Mongo driver needs a source of serialiation information in order to know what to do with our queries. The most common way this usually works is via class maps (either implicit or explicit) , and a BsonClassMapSerializer. When dealing with loosely typed data we don’t have this information available to us however, and documentation is quite sparse on the matter.

After a bit of digging around though, there is a class in the driver that we can use… the BsonDocumentBackedClassSerializer. As the name suggests we need to use this in conjunction with a BsonDocumentBackedClass. Both of these classes are abstract, so we need to write a bit of boilerplate in order to use them.

Here’s the class:

And here’s the serializer:

Using the MongoDocument class

The MongoDocument class has an indexer, so basic usage of the mongo document class works like this:

There’s a couple of cool things at play here… the serializer takes care of generating an _id for us by implementing IBsonIdProvider members GetDocumentId and SetDocumentId. The document class itself also has an implicit cast operator back to BsonDocument for ease of use when you need more granularity. Seems simple? It is!

Registering concrete members with the serializer

There is one more thing that I’d like to elaborate on a little bit, as you may find it useful to get a little bit more flexibility out of your loosely typed MongoDocument. If you look closely at the code above, you’ll see this property in the class:

[BsonId]
public ObjectId Id { get; set; }

And then correspondingly in the constructor for the serializer:

this.RegisterMember("Id", "_id", ObjectIdSerializer.Instance, typeof(ObjectId), null);

This allows us to control how our document gets serialized, and also how it behaves in Linq. Given these lines, the following is perfectly valid and works fine, even though the value itself is stored in the BsonDocument backing the class:

var record = mongoCollection.AsQueryable().Where(o => o.Id == ObjectId.Parse("ABCDE1234"));

You can add more of these if you like… just add a property and a corresponding register member call… the parameters should be fairly straightforward, just make sure to pick the appropriate serializer and type.

Just the start

I’m not sure why the BsonDocumentBackedClass and serializer aren’t more well documented. It seems like up until now they have only really seen internal use, but we are using this code in a project that is nearing completion, it’s stable and working really well for us.

There is much more that we can do with MongoDb and Linq by using this code, and in the next post in this series I’ll be exploring how we can work with nested objects and child collections by controlling serialization of our MongoDocument even further.

Don’t forget, you can use this in conjunction with Linq to Querystring and the [] notation to combine your loosely typed data structures with the power of OData. Why not give it a try today!

Pete

References:

http://docs.mongodb.org/ecosystem/tutorial/use-linq-queries-with-csharp-driver/
https://github.com/Roysvork/mongo-csharp-driver
https://nuget.org/packages/mongocsharp.linqindexers/
http://docs.mongodb.org/ecosystem/tutorial/serialize-documents-with-the-csharp-driver/
http://api.mongodb.org/csharp/1.8.1/html/225cb105-7edc-9bdf-9b2d-f9232bda4623.htm
https://github.com/Roysvork/LinqToQuerystring#general

Advertisements

From → MongoDB, Web API

One Comment
  1. Louise permalink

    Hi Pete,
    Thanks for your awesome work on this!
    The examples in you article seem to be missing though… do you think you could provide a link to the class and the serialiser? I’m a bit stuck on how to get loosely typed stuff out of Mongo
    Thanks again

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: