如何使用BsonClassMap更改MongoDB C#Driver类的反序列化方式?

时间:2018-04-10 19:36:34

标签: c# mongodb mongodb-.net-driver

由于过滤器我应用于我的更改流(在SO:How do you filter updates to specific fields from ChangeStream in MongoDB讨论),我得到的是BsonDocument而不是ChangeStreamDocument对象。来自ChangeStreamDocument的这个BsonDocument唯一不同的是它包含一个名为" tmpfields"的额外元素。

在我的场景中,我仍然需要ResumeToken和文档中的其他元素,所以我想将这个BsonDocument转换为ChangeStreamDocument对象。我的第一次尝试是使用BsonSerializer.Deserialize<ChangeStreamDocument<BsonDocument>>( doc),其中doc是我回来的BsonDocument。但是,由于它具有额外的tmpfields元素,因此不允许这样做。

我试图注册BsonClassMap,因为ChangeStreamDocument类是C#驱动程序的一部分,我无法将[BsonIgnoreExtraElements]属性添加到类中,但我没有成功:

BsonClassMap.RegisterClassMap<ChangeStreamDocument<BsonDocument>>(cm =>
{
    cm.AutoMap();
    cm.SetIgnoreExtraElements(true);
});

虽然AutoMap()没有工作,但我得到了关于&#34的例外情况;找不到匹配的创作者&#34;。我试图cm.MapCreator(...),但也没有成功。我调出了AutoMap()调用(只留下了SetIgnoreExtraElements行)并且得到了关于它无法匹配属性(_id等)的错误。所以我为每个属性尝试了cm.MapProperty(c => c.DocumentKey).SetElementName("documentKey")之类的行,但是当我使用Deserialize()方法时它们从未被设置 - 它们被保留为null。

目前,我已经恢复使用doc["field"].AsXYZ方法从BsonDocument获取我需要的值,但我想学习一种更好的方法来实现这一点。

正在使用RegisterClassMap正确的方法吗?如果是这样,我错过了什么?

1 个答案:

答案 0 :(得分:0)

  

我无法将[BsonIgnoreExtraElements]属性添加到类

如果你只是想忽略额外的字段。您只需添加一个额外的聚合管道$project即可删除该字段。

例如

var options = new ChangeStreamOptions { FullDocument = ChangeStreamFullDocumentOption.UpdateLookup };
var addFields = new BsonDocument { { "$addFields", new BsonDocument { { "tmpfields", new BsonDocument { { "$objectToArray", "$updateDescription.updatedFields" } } } } } };
var match = new BsonDocument { { "$match", new BsonDocument { { "tmpfields.k", new BsonDocument { { "$nin", new BsonArray{"a", "b"} } } } } } };

// Remove the unwanted field. 
var project = new BsonDocument { {"$project", new BsonDocument { {"tmpfields", 0 } } } };
var pipeline = new[] { addFields, match, project };

var cursor = collection.Watch<ChangeStreamDocument<BsonDocument>>(pipeline, options);

var enumerator = cursor.ToEnumerable().GetEnumerator();
while(enumerator.MoveNext())
{
     ChangeStreamDocument<BsonDocument> doc = enumerator.Current;
     Console.WriteLine(doc.DocumentKey); 

 }