【问题标题】:How can I use BsonClassMap to change the way a MongoDB C# Driver class is deserialized?如何使用 BsonClassMap 更改 MongoDB C# Driver 类的反序列化方式?
【发布时间】:2018-04-10 19:36:33
【问题描述】:

由于我应用到我的变更流的过滤器(在 SO:How do you filter updates to specific fields from ChangeStream in MongoDB 讨论),我得到的是 BsonDocument 而不是 ChangeStreamDocument 对象。此 BsonDocument 与 ChangeStreamDocument 的唯一不同之处在于它包含一个名为“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() 不起作用,但我收到了关于“找不到匹配的创建者”的异常。我尝试cm.MapCreator(...),但也没有成功。我调用了AutoMap()(只留下了 SetIgnoreExtraElements 行)并得到了关于它无法匹配属性(_id 等)的错误。所以我对每个属性都尝试了cm.MapProperty(c =&gt; c.DocumentKey).SetElementName("documentKey") 这样的行,但是当我使用Deserialize() 方法时它们从未设置过——它们被保留为空。

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

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

【问题讨论】:

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


    【解决方案1】:

    我无法将 [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); 
    
     }
    

    【讨论】:

    • 我在之前的尝试中已经完成了投影,但我认为我的 Watch 方法的泛型类型参数需要与管道 (BsonDocument) 的类型相匹配。很高兴知道我按照你的描述做了。知道如何从 BsonDocument 转换为不同的类型,而不必手动匹配属性,或者不必转换为 JSON 然后重新解析,这仍然会有所帮助。
    猜你喜欢
    • 1970-01-01
    • 2010-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-30
    • 2013-09-09
    相关资源
    最近更新 更多