-
Type:
Bug
-
Resolution: Fixed
-
Priority:
Unknown
-
Affects Version/s: 3.4.0
-
Component/s: None
-
None
-
None
-
Fully Compatible
-
Dotnet Drivers
-
Not Needed
-
None
-
None
-
None
-
None
-
None
-
None
Summary
Upsert with FindOneAndUpdateAsync does not set correct discriminator for hierarcal documents. It does correctly work with UpdateOneAsync. FindOneAndUpdateAsync created document has a string discriminator when it should be an array with hierarchical types.
Driver version: 3.4
topology: standalone
How to Reproduce
Example console application:
_using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver;
using MongoDB.Driver.Core.Events;
BsonSerializer.RegisterSerializer(new GuidSerializer(GuidRepresentation.Standard));
BsonClassMap.RegisterClassMap<Animal>();
BsonClassMap.RegisterClassMap<Cat>();
BsonClassMap.RegisterClassMap<Dog>();
BsonClassMap.RegisterClassMap<Lion>();
BsonClassMap.RegisterClassMap<Tiger>();
var connectionString = "mongodb://localhost/db?directConnection=true";
var settings = MongoClientSettings.FromUrl(new MongoUrl(connectionString));
settings.ClusterConfigurator = builder =>
{
builder.Subscribe<CommandStartedEvent>(e =>
{
Console.WriteLine($"Command
-> {e.Command.ToJson()}");
});
};
var client = new MongoClient(settings);
// Bootstrap data
var collection = client.GetDatabase("db").GetCollection<Animal>("animals");
var lion1 = new Lion()
{
Id = Guid.NewGuid(), Name = "Lion1"
};
var updateDefinition1 = Builders<Lion>.Update
.SetOnInsert(l=>l.Id, lion1.Id)
.Set(l => l.Name, lion1.Name);
await collection.OfType<Lion>().FindOneAndUpdateAsync(f=>f.Name == lion1.Name,updateDefinition1, new FindOneAndUpdateOptions<Lion>{ IsUpsert = true });
var lion2 = new Lion()
{
Id = Guid.NewGuid(), Name = "Lion2"
};
var updateDefinition2 = Builders<Lion>.Update
.SetOnInsert(l=>l.Id, lion2.Id)
.Set(l => l.Name, lion2.Name);
await collection.OfType<Lion>().UpdateOneAsync(f=>f.Name == lion2.Name,updateDefinition2, new UpdateOptions{ IsUpsert = true });
var cats = (await collection.OfType<Cat>().FindAsync(f=> true)).ToList();
var catCount = cats.Count;
//catCount is 1, should be 2
//Contains only the document inserted via UpdateOneAsync, does not contain inserted via FindOneAndUpdateAsync
/*
*{
"_id" : UUID("abd81744-fdd3-4dd2-9ac0-9af43c824fdf"),
"Name" : "Lion1",
"_t" : "Lion"
}
{
"_id" : UUID("7bb7b4b1-7559-4a9f-9f58-c27a5072c53f"),
"Name" : "Lion2",
"_t" : [
"Animal",
"Cat",
"Lion"
]
}
*/
[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof(Cat), typeof(Dog))]
public class Animal
{
public Guid Id
}_
[BsonKnownTypes(typeof(Lion), typeof(Tiger))]
_public class Cat : Animal
{
}
public class Dog : Animal
{
}
public class Lion : Cat
{
public string Name { get; set; }
}
public class Tiger : Cat
{
}_
Actual Result:
{ "_id" : UUID("abd81744-fdd3-4dd2-9ac0-9af43c824fdf"), "Name" : "Lion1", "_t" : "Lion" } { "_id" : UUID("7bb7b4b1-7559-4a9f-9f58-c27a5072c53f"), "Name" : "Lion2", "_t" : [ "Animal", "Cat", "Lion" ] }
Expected result:
{ "_id" : UUID("abd81744-fdd3-4dd2-9ac0-9af43c824fdf"), "Name" : "Lion1", "_t" : [ "Animal", "Cat", "Lion" ] } { "_id" : UUID("7bb7b4b1-7559-4a9f-9f58-c27a5072c53f"), "Name" : "Lion2", "_t" : [ "Animal", "Cat", "Lion" ] }