Search code examples
c#mongodbmongodb-.net-driver

How to deserialize a nested Document into a specific class object?


I'm new to MongoDb and I'm attempting to serialize an array of Documents that are nested within a parent document into a specific class object.

My Document object looks like this:

Project
{
    "_id" : ObjectId("589da20997b2ae4608c99173"),
    // ... additional fields
    "Products" : [ 
        { 
            "_id" : ObjectId("56971340f3a4990d2c199853"),
            "ProductId" : null,
            "Name" : null,
            "Description" : null,
            // ... quite a few more properties
            "Properties" : null 
        }
    ],
    "CreatorUserId" : LUUID("af955555-5555-5555-5555-f1fc4bb7cfae")
}

So basically its a Document named Project that contains a nested array of Product Documents.

Here are what the current classes look like:

public class Project : BaseClasses {
    public ObjectId ParentCreatorUserIdProject { get; set; }  
    // ... additional Fields 
    public IEnumerable<IProjectItem> ProjectItems { get; set; } 
    //public IEnumerable<IProductDetails> Products { get; set; }
}

[DataContract][Serializable]
[BsonIgnoreExtraElements][MongoCollection("products")]
public class Product {
    public string Name { get; set; } 
    public string Description { get; set; 
    // .. a bunch of Fields
} 

Current Behavior

Currently the Project document comes back with a serialized array of Product.

Desired Behavior

I would like the Document to come back with a serialized array of ProjectItems. The ProjectItems class is straightforward:

[Serializable]
[BsonIgnoreExtraElements]
public class ProjectItem {
    public string Name { get; set; } 
    public string Description { get; set; 
    // .. a handful of Fields
}

My Attempt

I have attempted to create a mapping using BsonClassMap however, I just don't know enough about this class type despite having read the entire document on mapping. I should note that I have defined this class map with the previous developers other mappings and am sure (Unit Tests) that they execute.

  BsonClassMap.RegisterClassMap<ProjectItem>(cm => {
      cm.AutoMap();
      cm.SetDiscriminator("ProjectItem");
      cm.SetDiscriminatorIsRequired(true);
  });

Unfortunately the document still gets serialized into an array of Product.

My Question

How can I serialize this nested array of Products into an array of ProjectItem classes?


Solution

  • So the answer turns out to be pretty simple... Whatever type you stored it as is what you want to set as your discriminator.

      BsonClassMap.RegisterClassMap<ProjectItem>(cm => {
          cm.AutoMap();
          cm.SetDiscriminator("Product"); // <--- it was stored as a Product
          cm.SetDiscriminatorIsRequired(true);
      });
    

    Let's see another example for my fellow MongoDb newbies... if your Product was originally stored as a ProductDetails your object would have an _t in the database. The _t tells MongoDb what type it was stored as.

    So your object could look like this:

    "Products" : [ 
        { 
             "_t" : "ProductDetails",
             "_id" : ObjectId("56971340f3a4990d2c199853"),
             "ProductId" : null,
             "Name" : null,
             "Description" : null,
             // ... quite a few more properties
             "Properties" : null 
        }
    ]
    

    Since our Product was stored with a discriminator type of "ProductDetail", we'd serialize it into a ProjectItem like this:

      BsonClassMap.RegisterClassMap<ProjectItem>(cm => {
          cm.AutoMap();
          cm.SetDiscriminator("ProductDetails"); // <--- it was stored as a ProductDetails
          cm.SetDiscriminatorIsRequired(true);
      });