views:

43

answers:

1

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?

A: 

For this purpose you have to use DBRef.

To do this in c#, you have to change your campaign class like this

public class Campaign
{        
    public string Name { get; set; }
    public List<DBRef> Placements { get; set; }
}

And insert the reference document like this

List<DBRef> refList = new List<DBRef>() {firstSite,secondSite };


var firstCampaign = new Campaign
{
    Name = "first campaign",
    Placements = refList
};

campaignCollection.Save(firstCampaign);

I haven't tested the code, but this gives the hint how to accomplish this.

Cheers

Ramesh Vel
This worked thanks - although, what you could do instead of this is just use an Oid. DBRef is pretty bulky, and all you're using it for in this case is to get the ID so you can pull back the site.
mrdowns