0

I am trying to actually replace a collection of Objects of type Game in my Collection "Games".

I want to replace these Objects with entirely new Objects. I have researched a bit on MongoDB and I see that 'UpdateMany' will replace Fields with new values but that's not exactly what I want. I wish to replace the entire Object.

For reference, this is my Game class:

public class Game
{
  public Guid Id { get; set; }
  public string Title { get; set; }
  public string Developer { get; set; }
  public int ProjectId { get; set; }

  public Game()
  {
   this.Id = Guid.NewGuid();
 }
}

This is my method I am using to attempt a bulk Replace. I am passing in a ProjectId, so for all of the Game Objects that have a ProjectId = to the argument, replace the Object with a new Game Object.

 public static void ReplaceGame(int ProjectId, IMongoDatabase Database)
 {
   IMongoCollection<Game> gameCollection = Database.GetCollection<Game>("Game");
   List<Game> gameCollectionBeforeReplacement = gameCollection.Find(g => true).ToList();
   if (gameCollectionBeforeReplacement.Count == 0)
   {
     Console.WriteLine("No Games in Collection...");
     return;
    }

    var filter = Builders<Game>.Filter.Eq(g => g.ProjectId, ProjectId);
    foreach (Game game in gameCollection.AsQueryable())
        gameCollection.ReplaceOneASync(filter, new Game() { Title = "REPLACEMENT TITLE" });
    }

Not only does this take an excessive amount of time. I suspect it's because of the .AsQueryable() call but it also doesn't work. I am wondering how I can actually replace all instances picked up by my filter with new Game Objects.

4
  • You're not awaiting the async call there. Commented Jun 15, 2018 at 11:59
  • So would changing the method to public static async..and then in the foreach -> await gameCollection.ReplaceOneASync(filter, new Game() { Title = "REPLACEMENT TITLE" }; I am getting the exception: After applying the update, the (immutable) field '_id' was found to have been altered to _id Commented Jun 15, 2018 at 12:01
  • Well, you can't change an immutable field. I'm not very familiar with Mongo, but rather than doing a bulk update can you delete them and reinsert? Commented Jun 15, 2018 at 12:44
  • That seems to be the way to go. But, is there a way to maintain the order when deleting? Sorting is kind of taxing, though. Commented Jun 15, 2018 at 12:47

1 Answer 1

3

Consider the following code:

public virtual ReplaceOneResult ReplaceOne(TDocument replacement, int projId)
{
    var filter = Builders<TDocument>.Filter.Eq(x => x.ProjectId, projId);
    var result = Collection.ReplaceOne(filter, replacement, new UpdateOptions() { IsUpsert = false }, _cancellationToken);

    return result;
}

You will find that ReplaceOneResult has a property that tells you the matched count. This makes it possible for you to keep executing the ReplaceOne call until the matched count equals 0. When this happens, you know all documents in your collection that had the corresponding project id have been replaced.

Example:

var result = ReplaceOne(new Game() { Title = "REPLACEMENT TITLE" }, 12);
while (result.MatchedCount > 0)
    result = ReplaceOne(new Game() { Title = "REPLACEMENT TITLE" }, 12);

This makes it so that you don't need the call to the database before you start replacing.

However, if you wish to insert the same values for every existing game, I would suggest you to do an UpdateMany operation. There you can use $set to specify all required values. The code above is simply not performant, with going to the database for every single replace call.

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.