I'm writing C# code that writes to a Mongo database used by an existing Web app (written in PHP), so I need to not change the existing structure of the database. The database structure looks something like this:
{
"_id": ObjectId("5572ee670e86b8ec0ed82c61")
"name": "John Q. Example",
"guid": "12345678-1234-5678-abcd-fedcba654321",
"recordIsDeleted": false,
"address":
{
"line1": "123 Main St.",
"city": "Exampleville"
}
}
I read that in to a class that looks like this:
public class Person : MongoMappedBase
{
public ObjectId Id { get; set; }
public Guid Guid { get; set; }
public bool RecordIsDeleted { get; set; }
public string Name { get; set; }
public AddressData Address { get; set; }
// etc.
}
public class AddressData : MongoMappedBase
{
public string Line1 { get; set; }
public string City { get; set; }
// etc.
}
The reading code looks like:
var collection = db.GetCollection<Person>("people");
List<Person> people = collection.Find<Person>(_ => true).ToListAsync().Result;
(Note: I'm still in development. In production, I'm going to switch to ToCursorAsync()
and loop through the data one at a time, so don't worry about the fact that I'm pulling the whole list into memory.)
So far, so good.
However, when I write the data out, this is what it looks like:
{
"_id": ObjectId("5572ee670e86b8ec0ed82c61")
"name": "John Q. Example",
"guid": "12345678-1234-5678-abcd-fedcba654321",
"recordIsDeleted": false,
"address":
{
"_t": "MyApp.MyNamespace.AddressData, MyApp",
"_v":
{
"line1": "123 Main St.",
"city": "Exampleville"
}
}
}
Notice how the address
field looks different. That's not what I want. I want the address data to look just like the address data input (no _t
or _v
fields). In other words, the part that ended up as the contents of _v
is what I wanted to persist to the Mongo database as the value of the address
field.
Now, if I was just consuming the Mongo database from my own C# code, this would probably be fine: if I were to deserialize this data structure, I assume (though I haven't yet verified) that Mongo would use the _t
and _v
fields to create instances of the right type (AddressData
), and put them in the Address
property of my Person
instances. In which case, everything would be fine.
But I'm sharing this database with a PHP web app that is not expecting to see those _t
and _v
values in the address data, and won't know what to do with them. I need to tell Mongo "Please do not serialize the type of the Address
property. Just assume that it's always going to be an AddressData
instance, and just serialize its contents without any discriminators."
The code I'm currently using to persist the objects to Mongo looks like this:
public UpdateDefinition<TDocument> BuildUpdate<TDocument>(TDocument doc) {
var builder = Builders<TDocument>.Update;
UpdateDefinition<TDocument> update = null;
foreach (PropertyInfo prop in typeof(TDocument).GetProperties())
{
if (prop.PropertyType == typeof(MongoDB.Bson.ObjectId))
continue; // Mongo doesn't allow changing Mongo IDs
if (prop.GetValue(doc) == null)
continue; // If we didn't set a value, don't change existing one
if (update == null)
update = builder.Set(prop.Name, prop.GetValue(doc));
else
update = update.Set(prop.Name, prop.GetValue(doc));
}
return update;
}
public void WritePerson(Person person) {
var update = BuildUpdate<Person>(person);
var filter = Builders<Person>.Filter.Eq(
"guid", person.Guid.ToString()
);
var collection = db.GetCollection<Person>("people");
var updateResult = collection.FindOneAndUpdateAsync(
filter, update
).Result;
}
Somewhere in there, I need to tell Mongo "I don't care about the _t
field on the Address
property, and I don't even want to see it. I know what type of objects I'm persisting into this field, and they'll always be the same." But I haven't yet found anything in the Mongo documentation to tell me how to do that. Any suggestions?