1

I am currently working on an MVC application using MongoDB and I'm generally a rookie with development. This my first foray into MongoDB; I have zero formal training with Mongo and now I'm stuck. My question is:

What is the correct syntax for updating data in a Mongo database using the latest C# driver and linq?

I'm trying to update a single user's information which is represented by this "PersonDTO" object:

public class PersonDTO
{

    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string MongoID { get; set; }

    [Display(Name = "Last Name")]
    public string lastName { get; set; }

    [Display(Name = "First Name")]
    public string firstName { get; set; }

    [Display(Name = "Alias")]
    public string alias { get; set; }

    public PersonContactInfo contactInfo { get; set; }

    [BsonDateTimeOptions(Kind = DateTimeKind.Local, DateOnly = true)]
    [Display(Name = "Member Since")]
    public DateTime? dateJoined { get; set; }

    [BsonIgnoreIfNull]
    [BsonElement("subjectIds")]
    public List<string> AdminSubjectIds = new List<string>();

    [BsonIgnoreIfNull]
    [BsonElement("topicIds")]
    public List<string> ModeratorTopicIDs = new List<string>();

    public PersonDTO()
    {
        MongoID = string.Empty;
        lastName = string.Empty;
        firstName = string.Empty;
        alias = string.Empty;
        dateJoined = null;
    }
}

public class PersonContactInfo
{
    [Display(Name = "Email")]
    public string email { get; set; }

    [BsonIgnoreIfNull]
    [Display(Name = "Phone Number")]
    public string phoneNumber { get; set; }

    public PersonContactInfo()
    {
        email = string.Empty;
        phoneNumber = string.Empty;
    }

}

I have a predefined Mongo Context that I use in my service layer:

public class MongoClientContext
{
    public IMongoDatabase Db;
    public MongoClientContext()
    {
        var client = new MongoClient(Settings.Default.xxxConnectionString);
        Db = client.GetDatabase(Settings.Default.xxxDatabaseName);
    }

    public IMongoCollection<PersonDTO> People
    {
        get
        {
            return Db.GetCollection<PersonDTO>("person");
        }
    }

}

And although I don't have an issue inserting data using the following method:

    public async Task<PersonDTO> InsertUserAsync(PersonDTO newUser)
    {
        try
        {
            newUser.MongoID = ObjectId.GenerateNewId().ToString();
            DateTime today = DateTime.Now;
            newUser.dateJoined = today.Date;
            await ctx.People.InsertOneAsync(newUser);
        }

        catch (Exception ex)
        {
            string failMsg = "Failed to insert " + newUser.firstName + " " + newUser.lastName + ". Exception message: " + ex;
            newUser.MongoID = failMsg;
        }

        return newUser;
    }

I am having no luck finding the correct syntax to perform an update. I have only made it this far in the application watching (slightly outdated) tutorials and poring over stackoverflow answers. I know that much more experienced devs would be able to read through the driver documentation and figure this out on their own but I'm not knowledgeable enough to do that myself which is why I'm posting this question. My best guess so far has been this method:

    public async void UpdateUserAsync(PersonDTO thisUser)
    {
        try
        {
            var User = ctx.People.FindOneAndUpdateAsync(x => x.MongoID == thisUser.MongoID, thisUser);
            return;
        }

        catch
        {

        }
    }

But VS is warning me that "The type arguments for method 'IMongoCollection.FindOneAndUpdateAsync(FilterDefinition, UpdateDefinition, FindOneAndUpdateOptions, CancellationToken)' cannot be inferred from usage." And suggesting that I "Try specifying the type arguments explicitly."

I have been sitting here basically guessing for the last 45 minutes on how to get this to compile and work but I can't figure it out. Does anyone know to write this correctly? And can you explain what arguments it's looking for? I really don't understand this driver very well and I need some help.

Maksim Simkin
  • 9,561
  • 4
  • 36
  • 49

1 Answers1

1

In your case you are not doing any update you are doing replace, so you just replace all User properties with new. Usage is:

coll.ReplaceOne(x=>x.MongoID == thisUser.MongoID, thisUser);

If you don't want to replace complete Document, you could use update and update just certain properties, for example, set only firstname:

coll.UpdateOne(x=>x.MongoID == thisUser.MongoID, 
           Builders<PersonDTO>.Update.Set(x=>x.firstName, thisUser.firstName));

I mentioned synchrone methods, it works the same with asynchrone too.

Maksim Simkin
  • 9,561
  • 4
  • 36
  • 49
  • Thank you! So when you use Builders<> is that just constructing a new Bson Document with the correct formatting & flags? – Edward Knish Jan 06 '17 at 11:05
  • Using Builders i just configure how update bson will look like. On that case, it produce something like: db.people.update( { MongoId: "123456678" }, { firstName: "newFirstname", }, ) – Maksim Simkin Jan 06 '17 at 11:07
  • I've found it hard to find the best standard way to use this driver and this answer helps a lot. What types of operations / scenarios would I find myself better off using the asynchronous methods rather than the synchronous ones? I've stumbled on a few blogs that are adamant about sticking with the asynchronous methods whenever possible but I can't figure out why it's so beneficial for MongoDB – Edward Knish Jan 06 '17 at 11:13
  • @EdwardKnish asynchronous calls should be there, because db-call is an io Bound and you could want to handle it asynchrone. – Maksim Simkin Jan 06 '17 at 11:48