Define formatting dates and decimals in FindOptions in C# driver

I am trying to find a way to define the formatting for date and decimal types while I read data from Mongo using C# driver with Repository pattern. Below is the code which I use to define the FindOptions.


MongoBsonRespository<BsonDocument> DbBsonRepository = new MongoBsonRespository<BsonDocument>(collectionName);
DbBsonRepository.MapFindOptions(reportQuery);

public void MapFindOptions(ReportQuery reportQuery)
{
	int columnCount = 0;
	var findOptions = new FindOptions<TDocument>();
	List<ProjectionDefinition<TDocument>> projectionList = new List<ProjectionDefinition<TDocument>>();
	if (reportQuery.Columns != null && reportQuery.Columns.Count > 0)
	{
		foreach (ColumnBase columnInfo in reportQuery.Columns)
		{
			//build the projection definition for select
			FieldDefinition<TDocument> fieldDefinition = columnInfo.Name;
			projectionList.Add(Builders<TDocument>.Projection.Include(fieldDefinition));
			columnCount++;
		}
	}
    findOptions.Projection = Builders<TDocument>.Projection.Combine(projectionList);
	FindOptions = findOptions;
}

 using (IAsyncCursor<BsonDocument> cursor = DbBsonRepository.FindSync())
 {
     //the logic to read data
 }

My query here is, how do I specify formatting for date or decimal fields in the FieldDefinition itself ? or is there any other to solve this ? Thanks in advance.

Hi, @Saravanaram_Kumarasamy,

Welcome to the MongoDB Community Forums. I understand that you are wondering how to specify date and decimal formatting when working with BsonDocuments.

The data returned from MongoDB will be of type BsonDateTime or BsonDecimal128 (assuming that is how it is stored in the database). These are convertible to C# types such as DateTime or decimal. So you can format the data using standard .NET/C# constructs such as format strings and format specifiers. For example, to format a decimal as currency, you could use {price:C2}. (Note that you would first have to convert the BsonDecimal128 to a decimal (via ToDecimal()) in order to use C# format specifiers.

NOTE: Rather than working with BsonDocuments, you can map your documents to C# classes (AKA POCOs) and the serialization framework built into the driver will convert the BSON types to C# types for you. This behaviour can be controlled via BSON attributes, BsonClassMap<T>, and conventions.

Sincerely,
James

Hi @James_Kovacs,

Thanks for the reply.
I understand that date or decimal formatting can be applied on the BsonDocument after retrieval. But this I feel is a hit on performance as I will have to additionally loop through the records every time to format the desired fields.

And also I get to know from your reply that the type cast can be done by specifying the BSON attribute on the POCOs. This I can, but there are dynamic collections as well, so defining POCOs for all is not possible.

But is there a way, where I can specify the format for decimal/date fields, in the FieldDefinition/StringFieldDefinition or in the ProjectionList so that the formatting would have been done already while data retrieval from the database.

Thanks again!

If you want to perform the transformation on the server, you can use code such at the following:

using MongoDB.Bson;
using MongoDB.Driver;

var client = new MongoClient();
var db = client.GetDatabase("test");
var coll = db.GetCollection<Event>("events");

var query = coll.Aggregate().Project(x => new { Start = x.StartTime.ToString("%Y-%m-%d") });
Console.WriteLine(query);

record Event(ObjectId Id, string Title, DateTime StartTime, DateTime EndTime);

Note that my POCO is using DateTime because I need to be able to call DateTime.ToString in my Fluent Aggregate or LINQ query. I am projecting into an anonymous type, but you could just as easily project into a POCO where the date fields are strings.

This code will send the following MQL to the server. Note how Datetime.ToString was transformed into $dateToString.

aggregate([{ "$project" : { "Start" : { "$dateToString" : { "date" : "$StartTime", "format" : "%Y-%m-%d" } }, "_id" : 0 } }])

The format specifier string is passed through unaltered and uses the $dateToString format specifiers, not the .NET ones.

Sincerely,
James