Introduction to MongoDb with .NET part 15: object serialisation continued

Introduction

In the previous post we started looking into object serialisation in the MongoDb .NET driver. Serialisation attributes, like BsonElement help us declare the mapping between our C# objects and the corresponding documents. We can map JSON properties to C# properties, declare that a property is of a type that differs from its JSON counterpart and so on.

In this post we’ll look at some more examples of data serialisation in the MongoDb .NET driver. A good documentation is located on the MongoDb page dedicated to this topic. It goes through more advanced cases like supertypes and subtypes, custom serialisation and custom attributes.

More MongoDb serialisation options

Occasionally you may want to deviate from the standard serialisation mechanism: you can ignore certain properties or define a different property name. Serialisation attributes in MongoDb will help you a great deal here. They are similar to the DataMember, IgnoreMember etc. attributes in .NET serialisation. Examples:

Ignoring elements

To ignore a property use BsonIgnore:

public class Customer
{
	public string Name { get; set; }
	public string Address { get; set; }
	IEnumerable<string> Telephones { get; set; }
	[BsonIgnore]
	public string PublicPage { get; set; }
}

The PublicPage property will not be serialised in the BSON document.

Ignore NULL values

public class Customer
{		
	public string Name { get; set; }
	[BsonIgnoreIfNull]
	public string Address { get; set; }
}

Serialise private fields

We’ve already seen the BsonElement attribute in action. It has another purpose. By default private fields are not serialised. You can use the empty BsonElement to include it in the serialisation:

public class Customer
{		
	public string Name { get; set; }
	public string Address { get; set; }
	IEnumerable<string> Telephones { get; set; }
	[BsonElement]
	private WebPage PublicPage { get; set; }
}

Different data types

Declare how the property will be represented in BSON, i.e. under which type, using the BsonRepresentation attribute:

public class Customer
{
	[BsonRepresentation(MongoDB.Bson.BsonType.Double)]
	public decimal TotalOrders { get; set; }
}

The .NET decimal type has no equivalent in BSON, it’s treated as a string which makes sorting and comparing inefficient. It’s better to cast it to a BSON double which is close enough.

The ID field

We’ve seen before that the unique ID field is called “_id” by default and is of type ObjectId. You can declare a different ID field using the BsonId attribute:

public class Customer
{
	[BsonId]
	public int CustomerId { get; set; }
}

The ID will still be serialised as “_id” in the document but you can refer to it as “CustomerId” in the POCO.

Dates

Dates are always a different beast with all the time zones and formats. MongoDb translates all local dates to UTC automatically when a date field is serialised. However, it can create problems when the date is deserialised. You’ll by default get the UTC date whereas you may expect the local one. I think it’s always wise to work only with UTC in your domains and convert dates for views only, but you can use the BsonDateTimeOptions attribute to override the default behaviour:

public class Customer
{
	[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
	public DateTime CustomerSince { get; set; }
}

This way the UTC date stored in the document will be converted to the local time zone of the computer.

In case you only want to store the “date” part of a date, i.e. without the hours:minutes:seconds bit then use the DateOnly parameter of BsonDateTimeOptions:

public class Customer
{
	[BsonDateTimeOptions(Kind = DateTimeKind.Local, DateOnly = true)]		
	public DateTime CustomerSince { get; set; }
}

There are many other serialization cases we haven’t covered here. The goal was mainly to make you aware of the basic data serialisation options. For more details you can consult the MongoDb documentation page referenced above. For more customised serialisation you can read this page.

Zipcodes collection

Let’s extend the ModelContext class with a handle on the zipcodes collection as well. The zipcodes collection is definitely simpler than that of the restaurants collection. Add the following class to the Repository folder:

using MongoDB.Bson.Serialization.Attributes;
using Newtonsoft.Json;

namespace MongoDbDotNet.Repository
{
	[BsonIgnoreExtraElements]
	public class ZipCodeDb
	{
		[BsonId]
		[BsonElement(elementName: "_id")]
		public string Id { get; set; }
		[BsonElement(elementName: "city")]
		public string City { get; set; }
		[BsonElement(elementName: "loc")]
		public double[] Coordinates { get; set; }
		[BsonElement(elementName: "pop")]
		public int Population { get; set; }
		[BsonElement(elementName: "state")]
		public string State { get; set; }

		public override string ToString()
		{
			return JsonConvert.SerializeObject(this, Formatting.Indented);
		}
	}
}

The ModelContext class can be extended with the following property:

public IMongoCollection<ZipCodeDb> ZipCodes
{
	get { return Database.GetCollection<ZipCodeDb>(ConfigurationRepository.GetConfigurationValue("ZipCodesCollectionName", "¨zipcodes")); }
}

Let’s test it from the Main method:

ZipCodeDb firstInMassachusetts = modelContext.ZipCodes.FindSync(z => z.State == "MA").FirstOrDefault();
Console.WriteLine(firstInMassachusetts);

The above example gives a preview of a different style of querying than we saw before. The previous example was based on a filter built from the static Builders class. The above example demonstrates a LINQ query. We want to find the first restaurant in Massachusetts. Here is what I got in the console window:

{
  "Id": "01001",
  "City": "AGAWAM",
  "Coordinates": [
    -72.622739,
    42.070206
  ],
  "Population": 15338,
  "State": "MA"
}

In the next post we’ll look at how to query data in the .NET driver.

You can view all posts related to data storage on this blog here.

Advertisement

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

2 Responses to Introduction to MongoDb with .NET part 15: object serialisation continued

  1. Danish says:

    Thank you for this great series of articles. I stumbled on your blog while researching MongoDB in .NET space. I am in the planning phase of a building an mvc application which actually deserves an EAV model but after reading the negativity on it, I am considering NoSQL databases (Mongodb to be specific) for this purpose. Although the internet seems to be divided on when and when not to use, One of the requirements of the system is a huge load of reporting on the data collected from the mvc application with plenty of aggregation functions and I am reading that BI is not the strongest area of MongoDB.

    Having said that, In the start of of this series, you mentioned that there are some good use cases of MongoDB and your company has adapted MongoDB to a good extent with a number of applications. Do you mind giving some information what type of applications were they and why MongoDB was a good fit?

    • Andras Nemes says:

      In my particular case I started using MongoDb a number of years ago for its ease of use and speed. I needed a data store which can easily scale and that can consume a lot of inserts in a short amount of time – we’re talking about seconds – while another application reads from it almost equally quickly. I tested our traditional MS SQL database and then MongoDb as well because it was promoted in our area at that time and I was interested to learn something new. MongoDb instantly fared a lot better without any special optimisation like indexing so I sticked to it. Also, adding new nodes to a MongoDb cluster is almost too easy compared to the traditional relational databases and that was also an important consideration to enable quick and easy scaling.

      We use MongoDb in 2 applications we’ve built and both had speed and scalability as major considerations for their data stores. They both write a large amount of data in quick succession to the collections and reads must be equally fast and reliable.

      BI in MongoDb has come a long way recently. I think when people say BI is not strong in MongoDb it’s like saying today that Java is slow. Well, it was kind of slow in its early versions but people still sticking to this argument against Java have not followed along the improvements made to the JVM during the past years. The same holds true of MongoDb. It offers a wide range of techniques around MapReduce in the form of projections and aggregates. It’s true that you won’t get a fancy GUI tool like in MS SQL and you’ll need to write your own JSON queries but that is not equivalent to BI not being strong in MongoDb. On the contrary I would say that MongoDb is a good fit even for Big Data queries. So I think BI is strong in MongoDb as far as querying techniques are concerned. On the other hand there are no automated tools like reporting services, you’d need to roll your own solution there.

      I’ll take up aggregations in MongoDb in this series but I’m not yet sure when I get there, maybe next week or the week after that.

      //Andras

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 )

Facebook photo

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

Connecting to %s

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

%d bloggers like this: