Как читать данные из Mongodb, которые имеют повторяющееся имя элемента в C#

Я использую MongoDB.Drivers в моем приложении C# MVC для связи с базой данных 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 Data Pic

На изображении выше вы можете видеть, что у меня есть несколько столбцов под названием DuplicateCol с разными значениями. Когда я попытался прочитать эти данные в c# с помощью MongoDB.Driver Я получил следующую ошибку: InvalidOperationException: Duplicate element name 'DuplicateCol'.

При вставке дубликата имени элемента я использовал AllowDuplicateNames=true из BsonDocument Объект, как показано ниже. (Он вставляет повторяющееся имя элемента без ошибок.)

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);

Примечание: эта схема должна быть. Я не могу это изменить.

Пожалуйста, дайте мне предложения, чтобы исправить эту проблему. Любая помощь будет высоко оценен..

Благодарю.

2 ответа

Решение

Если ничто иное не поможет, вы просмотрели другие ответы и комментарии и по-прежнему считаете, что вы обязательно должны придерживаться схемы, описанной в вашем вопросе, вы можете воспользоваться следующим способом. Создайте класс так:

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 не имеет сеттера):

// 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);
                }
            }
        }
    }
}

Ошибка, которую вы получаете, является дизайном

InvalidOperationException: Duplicate element name 'DuplicateCol'

Как сказал CodeFuller, ключи документа MongoDB должны быть уникальными. Если вам нужен документ, содержащий повторяющиеся имена полей, и вы не можете изменить эту схему, MongoDB может оказаться не лучшим решением для базы данных... Я не знаю, какое из них будет честным. Хотя представляется возможным сохранить дубликаты ключей, используя:

AllowDuplicateNames=true

Я полагаю, что у вас будут проблемы с запросами и индексацией, среди прочего.

Можно привести аргумент, что эта схема является очень странным требованием. Более подходящей схемой может быть:

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

Здесь у вас есть одно свойство (duplicateCol), которое представляет собой массив, который принимает несколько строк.

Другие вопросы по тегам