mongodb-csharp driver - how to save a property as a reference rather than embedded?

Viewed 4113

We're doing a little spike on Mongo DB for our C#.NET project to see if it's right for us, and I've run into a little problem with the mongodb-csharp driver by samus that I'm not sure how to implement.

Given the following simplified model:

public class Campaign
{        
    public string Name { get; set; }
    public IEnumerable<Placement> Placements { get; set; }
}

public class Placement
{
    public string Name { get; set; }

    //this should be a reference rather than included in the collection
    public Site Site { get; set; }
}

//this should be its own collection, and not embedded anywhere
public class Site
{
    public string Name { get; set; }
}

We're trying to figure out, as the comments above suggest, how to save Site as a referenced type rather than embedded in Placement. Site is its own top-level collection that changes independently from each Campaign.

Ideally, I'd like to do this using the MongoConfigurationBuilder rather than having to modify my POCOs. I just can't seem to find any documentation on how this is accomplished.

I was hoping it would be as easy as:

var config = new MongoConfigurationBuilder();

config.Mapping(mapping =>
{
    //maybe some more configuration here?
    mapping.Map<Site>();
    mapping.Map<Campaign>();
});

But that's still embedding Sites when I use the following code:

var db = mongo.GetDatabase("foo");

var campaignCollection = db.GetCollection<Campaign>();
var siteCollection = db.GetCollection<Site>();

var firstSite = new Site{Name = "first site"};
var secondSite = new Site{Name = "second site"};

var firstCampaign = new Campaign
{
    Name = "first campaign",
    Placements = new List<Placement>
    {
        new Placement{Name = "first placement", Site = firstSite},
        new Placement{Name = "second placement", Site = secondSite}
    }
};

siteCollection.Save(firstSite);
siteCollection.Save(secondSite);

campaignCollection.Save(firstCampaign);

This is giving us:

{ "_id" : ObjectId("4ca9f1db54730000000010cb"), 
  "Name" : "first campaign", 
  "Placements" : [
    {
      "Name" : "first placement",
      "Site" : { "Name" : "first site" }
    },
    {
      "Name" : "second placement",
      "Site" : { "Name" : "second site" }
    }
  ]}

{ "_id" : ObjectId("4ca9f1db54730000000010c9"), "Name" : "first site" }
{ "_id" : ObjectId("4ca9f1db54730000000010ca"), "Name" : "second site" }

Whereas we want something more like:

{ "_id" : ObjectId("4ca9f1db54730000000010cb"), 
  "Name" : "first campaign", 
  "Placements" : [
    {
      "Name" : "first placement",
      "Site" : ObjectId("4ca9f1db54730000000010c9")
    },
    {
      "Name" : "second placement",
      "Site" : ObjectId("4ca9f1db54730000000010ca")
    }
  ]}

{ "_id" : ObjectId("4ca9f1db54730000000010c9"), "Name" : "first site" }
{ "_id" : ObjectId("4ca9f1db54730000000010ca"), "Name" : "second site" }

I'm not sure if that's the exact document we'd end up with, but you get the point.

I feel as though I'm missing something obvious, but without better documentation on this aspect of the driver, I'm sort of shooting in the dark. I even looked through the tests in the source and couldn't figure it out.

Does anyone know how to do this? Is it possible?

1 Answers
Related