如何从 Mongodb 中读取在 c# 中具有重复元素名称的数据

How to read data from Mongodb which have duplicate element name in c#

我在我的 C# MVC 应用程序中使用 MongoDB.Drivers 与 Mongodb 数据库通信。

C#代码

            var client = new MongoClient("mongodb://localhost:27012");
            var db = client.GetDatabase("Test_DB");
            var collection = db.GetCollection<BsonDocument>("TestTable");
            var tData = await collection.FindAsync(new BsonDocument(true)); // I used - new BsonDocument(true)  to specify allow duplicate element name while read data.

MongoDB资料图片

在上图中,您可以看到我有多个名为 DuplicateCol 的列,它们具有不同的值。 当我尝试使用 MongoDB.Driver 读取 c# 中的这些数据时,出现以下错误:InvalidOperationException: Duplicate element name 'DuplicateCol'.

虽然插入重复的元素名称,但我使用了 BsonDocument 对象的 AllowDuplicateNames=true,如下所示。 (插入重复的元素名称没有错误。)

BsonDocument obj = new BsonDocument();
obj.AllowDuplicateNames = true;
obj.Add("DuplicateCol", "Value_One");
obj.Add("propone", "newVal");
obj.Add("DuplicateCol", "Value_Two");
.... // other properties with value 
await collection.InsertOneAsync(obj);

注意:此架构是必须的。我改不了。

请提供解决此问题的建议。 任何帮助将不胜感激..

谢谢。

您收到的错误是设计使然

InvalidOperationException: Duplicate element name 'DuplicateCol'

正如 CodeFuller 所说,MongoDB 文档键应该是唯一的。如果您需要一个包含重复字段名称的文档并且您不能更改此模式,MongoDB 可能不是适合您的数据库解决方案……老实说,我不知道哪个会。尽管似乎可以使用以下方法保存重复键:

AllowDuplicateNames=true

我想您会遇到查询和索引等方面的挑战。

有人认为这种模式是一个非常奇怪的要求。更合适的架构可能是:

{
    "_id" : ObjectId("xxx"),
    "propTest" : 0,
    ...
    "duplicateCol": [ "Value_Two", "Value_One" ]
}

这里有一个 属性 (duplicateCol),它是一个接受多个字符串的数组。

如果没有其他帮助,您查看了其他答案和评论,并且仍然认为您绝对必须保留问题中描述的设计,您可以使用以下 hack。像这样创建 class:

class AlwaysAllowDuplicateNamesBsonDocumentSerializer : BsonDocumentSerializer {
    protected override BsonDocument DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) {
        if (!context.AllowDuplicateElementNames)
            context = context.With(c => c.AllowDuplicateElementNames = true);
        return base.DeserializeValue(context, args);
    }

    public override BsonDocument Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) {
        if (!context.AllowDuplicateElementNames)
            context = context.With(c => c.AllowDuplicateElementNames = true);
        return base.Deserialize(context, args);
    }
}

这是 BsonDocument 的自定义序列化程序,它在反序列化时始终设置 AllowDuplicateElementNames。然后你需要一些反射来覆盖默认的 BsonDocument 序列化器(因为 BsonDocumentSerializer.Instance 没有 setter):

// get __instance field, which is backing field for Instance property
var instanceField = typeof(BsonDocumentSerializer).GetField("__instance", BindingFlags.Static | BindingFlags.NonPublic);
// overwrite with our custom serializer
instanceField.SetValue(null, new AlwaysAllowDuplicateNamesBsonDocumentSerializer());

通过在启动时的某处执行此操作,您将能够读回具有重复属性的文档。

完整的测试代码:

static void Main(string[] args) {
    var instanceField = typeof(BsonDocumentSerializer).GetField("__instance", BindingFlags.Static | BindingFlags.NonPublic);
    instanceField.SetValue(null, new AlwaysAllowDuplicateNamesBsonDocumentSerializer());
    TestMongoQuery();
    Console.ReadKey();
}

static async void TestMongoQuery() {
    var client = new MongoClient();
    var db = client.GetDatabase("Test_DB");            
    var collection = db.GetCollection<BsonDocument>("TestTable");
    using (var allDocs = await collection.FindAsync(FilterDefinition<BsonDocument>.Empty)) {
        while (allDocs.MoveNext()) {
            foreach (var doc in allDocs.Current) {
                var duplicateElements = doc.Elements.Where(c => c.Name == "DuplicateCol");
                foreach (var el in duplicateElements) {
                    Console.WriteLine(el.Name + ":" + el.Value);
                }
            }
        }
    }
}