MongoDB含互斥字段集合的通用序列化方案问询
通用化MongoDB互斥字段的序列化方案
问题背景
你的MongoDB集合中每个Signals文档仅包含_id、timestamp和一个有值的互斥字段(其余字段为null或不存在),当前通过硬编码所有可能字段的方式实现序列化,希望对字段名称做通用化处理,避免硬编码。
可行方案
方案1:用字典存储动态字段
直接用Dictionary<string, double[]>替代硬编码字段,配合MongoDB序列化特性,既能保留原字段名结构,又无需预先定义所有可能的键:
public class Signals : DomainClassBase { public DateTime timestamp { get; set; } // 键为字段名(如"JLVib"),值为对应数组,序列化后直接生成原格式文档 [BsonDictionaryOptions(DictionaryRepresentation.Document)] public Dictionary<string, double[]> SignalData { get; set; } = new(); }
使用时只需往SignalData中添加唯一的键值对即可,序列化后文档结构和原硬编码方式完全一致。
方案2:自定义Bson序列化器
如果想保持类似原类的使用体验(无需显式操作字典),可以自定义序列化器处理动态字段:
- 定义仅含固定字段的基础类:
public class Signals : DomainClassBase { public DateTime timestamp { get; set; } [BsonIgnore] public string SignalName { get; set; } [BsonIgnore] public double[] SignalValues { get; set; } }
- 实现自定义序列化逻辑:
public class SignalsSerializer : IBsonSerializer<Signals> { public Signals Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { var doc = BsonDocumentSerializer.Instance.Deserialize(context, args); var signals = new Signals { timestamp = doc["timestamp"].ToDateTime() }; // 筛选出唯一非固定字段 var signalField = doc.Elements.First(e => e.Name != "_id" && e.Name != "timestamp"); signals.SignalName = signalField.Name; signals.SignalValues = signalField.Value.AsBsonArray.Select(v => v.AsDouble).ToArray(); return signals; } public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, Signals value) { var doc = new BsonDocument { {"timestamp", value.timestamp}, {value.SignalName, new BsonArray(value.SignalValues)} }; BsonDocumentSerializer.Instance.Serialize(context, args, doc); } public Type ValueType => typeof(Signals); }
- 给类标记序列化器:
[BsonSerializer(typeof(SignalsSerializer))] public class Signals : DomainClassBase { // 类内容同上 }
这种方式可以让你在代码中直接操作SignalName和SignalValues,序列化后依然生成符合原格式的文档。
方案3:使用动态类型(适合简单场景)
如果是临时场景或快速开发,可以直接用dynamic类型处理,但会损失类型安全性:
dynamic signalDoc = new ExpandoObject(); signalDoc.timestamp = DateTime.Now; signalDoc.JLVib = new double[] {1.0, 2.0}; // 直接序列化动态对象 var bsonDoc = BsonSerializer.Serialize(signalDoc);
反序列化时同样可以用dynamic读取,再转换为所需结构。
方案选择建议
- 追求简单直接选方案1,代码量最少,无需额外逻辑;
- 需要强类型约束且不想暴露字典选方案2,兼顾灵活性和类型安全;
- 临时场景或快速验证用方案3,不推荐生产环境大量使用。
内容的提问来源于stack exchange,提问作者Oiproks
相关产品推荐
相关产品推荐

