11

I am able to update a Document if the Document Exists using the Following

var filter = Builders<Neighborhood>.Filter.Eq(x => x.Id, neighborhood.Id);

var result = await collection.ReplaceOneAsync(filter,
             neighborhood,new UpdateOptions { IsUpsert = true });


[CollectionName("neighborhoods")]
[BsonIgnoreExtraElements(true)]
public class Neighborhood : IEntity<string>
{
 [BsonId(IdGenerator = typeof(GuidGenerator))]
 [BsonRepresentation(BsonType.ObjectId)]
 public string Id { get; set; }

 [BsonElement("name")]
 public string  Name    { get; set; }
}

How do Insert a Document if the Id = NULL and I want to return the updated result.

When Inserting a New Document NULL ID, A Record is created with a NULL Id, I added [BsonId(IdGenerator = typeof(GuidGenerator))] without any luck.

What am I doing wrong so a ObjectId can be generated for new records.

Liam
  • 27,717
  • 28
  • 128
  • 190
SPS101
  • 278
  • 1
  • 4
  • 12

1 Answers1

9

C# Driver thinks that Id is already filled. You need to add settings for Id field which allows driver to generate new Id.
There are two approaches:

  1. Add attribute [BsonIgnoreIfDefault] in your Neighborhood model.
  2. Setup in code

    BsonClassMap.RegisterClassMap<Neighborhood>(x =>
    {
        x.AutoMap();
        x.GetMemberMap(m => m.Id).SetIgnoreIfDefault(true);
    });
    

I prefer the second approach because you don't need to add reference to MongoDB.

MongoDB API proposes two methods:
1) ReplaceOneAsync returns ReplaceOneResult which has UpsertedId property

var filter = Builders<Neighborhood>.Filter.Where(x => x.Name == "somthing");
var replaceResult = await collection.ReplaceOneAsync(filter, entity, new UpdateOptions { IsUpsert = true });
return replaceResult.UpsertedId;

2) FindOneAndReplaceAsync allows you to select what you want - entity before changes or after. For our task we need after

var filter = Builders<Neighborhood>.Filter.Where(x => x.Name == "somthing");
var options = new FindOneAndReplaceOptions<Neighborhood, Neighborhood>
  {
     IsUpsert = true,
     ReturnDocument = ReturnDocument.After
  };
var updatedEntity = await collection.FindOneAndReplaceAsync(filter, entity, options);
rnofenko
  • 9,198
  • 2
  • 46
  • 56
  • Thanks, This Should help, Still not getting the Id to Generate, there may be other issues I need to look at – SPS101 Jan 05 '16 at 02:37
  • 1
    @SPS101, try `FindOneAndReplaceAsync`. I added an example to the answer. – rnofenko Jan 05 '16 at 04:25
  • 1
    Thanks, for the help, For Some Reason on Save the Id is generated, but on other commands the Id is not generated, So I am manually setting the objectId when null, still a work in progress but I can move forward. Thanks Again – SPS101 Jan 07 '16 at 05:33
  • Neither `FindOneAndReplace` or `ReplaceOneAsync` will set the the `[BsonRepresentation(BsonType.ObjectId)]` property, even with the `[BsonIgnoreIfDefault]` attribute. – Jeremy Jan 25 '23 at 00:13