2

I'm writing a wrapper around certain functions of mongodb to enforce certain buisiness policies (such as having a last modified date, a document version &c). These extra fields will not appear in the model and will be irrelevant and transparent to the person implementing against this library. This library will be generic.

Therefore using replaceOne is out of the question.

What I would like is some way of passing all fields in a person passed object to the Update builder - so I can use .Set/.Inc accordingly to add the other fields.

An example to demonstrate what I want is below:

public static async Task UpdatePerson(string name, Person person)
    {
        var client = new MongoClient("mongodb://localhost:27017");
        IMongoDatabase db = client.GetDatabase("test");

        IMongoCollection<Person> collection = db.GetCollection<Person>("people");

        var query = Builders<Person>.Filter
        .Eq("name", name);

        var update = Builders<Person>.Update
        //Something here - how do I pass my person's properties?
        .Set("lastModified", DateTime.Now)
        .Inc("version",1);

        await collection.UpdateOneAsync(query, update );
    }

//--

//In real life this'll work for other types, this is for demonstration only
public class Person
    {
        public string name {get;set;}
        public string surname {get;set;}
}

So how can I go about this, without, for instance, looping through properties using Reflection?

13
  • It is not clear what you want to achieve. Could you explain a bit more? Commented May 6, 2019 at 10:27
  • I would like to "replace" the current document with the passed one, whilst retaining all fields not otherwise specified, and allowing myself to add additional fields as needed. In short, I would like to $set with all the properties of the passed object. Commented May 6, 2019 at 11:18
  • you think about something like an extension method in a form of public static WithDefaultSetters(this UpdateBuilder self) { ... ? Where you automatically add your Set and Inc? Commented May 7, 2019 at 7:37
  • 2
    @user2110845 how about the idea of redesigning your schema into something like: { _id: ..., lastModifiedDate: ..., entity: { .... } } ? In that case you should be able to use $set to update the entity keeping other "metadata" fields unmodified Commented May 8, 2019 at 15:56
  • 1
    You can work with BsonDocument everywhere instead of working with defined classes, so you can change any field of that document before writing it, after reading it. You can convert any "normal" object (such as your Person class) into a BsonDocument using BsonExtensionMethods class' ToBsonDocument method. The other options is to have all your Person-like classes derive from a common class. Commented May 8, 2019 at 22:14

1 Answer 1

2
+100

Not sure if you are able to do this but the Mongodb Driver provides something called [BsonExtraElements].

public class Person
{
    public string name {get;set;}
    public string surname {get;set;}
    [BsonExtraElements]
    public Dictionary<string,object> AdditionalFields { get; set; }
}

What will happen is that anything that cant be serialized to the model will be filled into that dictionary, no matter the type. You can add to it as well and remove.

This will add no additional overhead to your database, The only downside to this is that querying this dictionary is somewhat not a great experience as you may need to cast specific keys to their relevant expected types.

If this is not viable I suggest the BSON approach recommended by Simon.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.