Avoid _id mapping

I have a legacy database with a collection with the following structure (simplified):

_id : ObjectId
Id: string
Value: Int32

And I have my C# class like this:

public string Id {get; set;}
public int Value {get; set;}

How can I map my class property Id with the Id (string) field in the collection, and not map with _id (ObjectId)?
I have tested many approaches but I usually got this exception message: Cannot deserialize a ‘String’ from BsonType ‘ObjectId’.

Hi :wave: @Bruno_Almeida,

Welcome to the MongoDB Community forums :sparkles:

By default, the C# driver maps the properties Id , id , and _id to the underlying _id database field. But you can override this behavior via attributes (e.g. [BsonId] ), configuration (BsonClassMap.SetIdMember ), or convention.

Note that the “Id member” is the field _id required by MongoDB. In this case, Id is just some arbitrary field in the database, but MongoDB still requires an _id field, which will populate with a new ObjectId if one is not provided.

So, I added the [BsonId] attribute and define the ObjectId _id in the schema and it worked. Sharing the code for your reference:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization;

public class MyClass
{
    [BsonId]
    public ObjectId _id { get; set; }
    public string Id { get; set; }
    public int Value { get; set; }
}

public class Program
{
    static async Task Main(string[] args)
    {
        // Set up a MongoDB client and database
        var client = new MongoClient("mongodb://localhost:27017/test");
        var database = client.GetDatabase("csharp");

        // Get a reference to the "mycollection" collection
        var collection = database.GetCollection<BsonDocument>("dotnetcore");
      
        // Insert a sample document into the collection
        var myObject = new MyClass { _id = ObjectId.GenerateNewId(), Id = "foo", Value = 42 };
        var document = myObject.ToBsonDocument();
        await collection.InsertOneAsync(document);

        // Query the collection for documents and deserialize them into instances of MyClass
        var filter = Builders<BsonDocument>.Filter.Empty;
        var documents = await collection.Find(filter).ToListAsync();
        var myObjects = new List<MyClass>();

        foreach (var y in documents)
        {
            var deserializedObject = BsonSerializer.Deserialize<MyClass>(y);
            myObjects.Add(deserializedObject);
        }

        // Do something with the deserialized objects
        foreach (var x in myObjects)
        {
            Console.WriteLine($"_id: {x._id}, Id: {x.Id}, Value: {x.Value}");
        }
    }
}

It returns the output:

_id: 6423c91b114e33a0106407be, Id: foo, Value: 42

However, there may be places where this mapping will not work as expected. For example, if this type is nested as a subdocument or contained in a list or dictionary. While it may work in some cases and maybe it won’t. Our recommended approach is to rename the Id database field to something more meaningful such as CustomerKey.

I hope it helps!

Best,
Kushagra

Thank you for your reply @Kushagra_Kesav.

I believe the best approach will be to rename the Id field (something I was avoiding) because I also don’t want to add Mongo references in the entity.

Greetings,
Bruno

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.