Search code examples
c#asp.netmongodbbsonmongodb.driver

Mapping BsonDocument to class but getting error


This is my BsonDocument that I extract from my MongoDb collection. I would like to deserialize (or map) this to an object/class that I made in C#.

{
  "_id" : ObjectId("5699715218a323101c663b9a"),
  "type": null,
  "text": "Hello this is text",
  "user": 
    {
      "hair": "brown",
      "age": 64
    }     
}

This is the class that I would like to map/deserialize the BsonDocument to. The fields inside my class are the only ones that I would like to retrieve.

    public class MyType
    {
        public BsonObjectId _id { get; set; }
        public BsonString text { get; set; }
    }

Currently this is how I am trying to do this but I am getting an error that "Element 'type' does not match any field or property of class MyType". I do not want to include "type" field in the MyType class.

 var collection = db.GetCollection<BsonDocument>("data_of_interest");
 var filter = new BsonDocument();
 var myData = collection.Find(filter).FirstOrDefault();
 MyType myObject = BsonSerializer.Deserialize<MyType>(myData);

I'm getting the error on the last line. In this example I am trying to do this for just one document to one instance of the MyType object. I am also interested in how to deserialize a whole collection to a list of the MyType object or something similar where it isn't for just one BsonDocument but for all of the documents in my collection.

Thanks for your time.


Solution

  • BsonIgnoreExtraElements

    Flag your class with the [BsonIgnoreExtraElements] attribute. That will tell the c# driver not to freak out if there isn't a 1:1 match between your class properties and the mongo record.

    [BsonIgnoreExtraElements]
    public class MyType
    {
        public BsonObjectId _id { get; set; }
        public BsonString text { get; set; }
    }
    

    With this approach, the type and user properties are going to be ignored.

    Add a "catch all" property for extra elements

    If you'd rather not ignore those elements, then you could add a catch all property that will house all your extra "undeclared" properties in a bson document.

    public class MyType
    {
        public BsonObjectId _id { get; set; }
        public BsonString text { get; set; }
        [BsonExtraElements]
        public BsonDocument CatchAll { get; set; }
    }
    

    With this approach, type and user will exist as properties of the .CatchAll property.

    What's the Advantage?

    One big advantage is that you can do a "findAndReplace" with the latter without losing the data from fields you aren't mapping.