I am using MongoDB.Drivers
in my C# MVC application to communicate with Mongodb database.
C# Code
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
In above image you can see I have multiple Columns called DuplicateCol
with different values.
When I tried to read these data in c#
using MongoDB.Driver
I got following error : InvalidOperationException: Duplicate element name 'DuplicateCol'.
While insert duplicate element name I used AllowDuplicateNames=true
of BsonDocument
object as below. (It insert duplicate element name without error.)
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);
Note: This Schema is Must. I can not altered it.
Please provide me suggestions to fix this Issue. Any help would be highly appreciated..
Thanks.
If nothing else helps, you reviewed other answers and comments, and still think you absolutely must keep design described in your question, you can use the following hack. Create class like this:
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);
}
}
This is custom serializer for BsonDocument
which always sets AllowDuplicateElementNames
while deserializing. Then you need a bit of reflection to overwrite default BsonDocument
serializer (because BsonDocumentSerializer.Instance
has no 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());
By doing that somewhere at startup you will be able to read back your documents with duplicated attributes.
Full code for test:
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);
}
}
}
}
}
The error you receive is by design
InvalidOperationException: Duplicate element name 'DuplicateCol'
As CodeFuller said, MongoDB document keys should be unique. If you need a document to contain duplicate field names and you cannot alter this schema, MongoDB might not be the right database solution for you....I don't know which one will to be honest. Although it does seem possible to save duplicate keys using:
AllowDuplicateNames=true
I imagine you will experience challenges with querying and indexing, among others.
An argument could be made that this schema is a very strange requirement. A more appropriate schema might be:
{
"_id" : ObjectId("xxx"),
"propTest" : 0,
...
"duplicateCol": [ "Value_Two", "Value_One" ]
}
Here you have a single property (duplicateCol) which is an array which accepts multiple strings.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With