37

If I want to read and write mongo data with a POCO

public class Thingy
{
     public string Foo {get;set;}
}
...
coll.Insert(new Thing(Foo = "hello"));

When I read back I get a failure saying that _id is an unexpected attribute (which it is). So then I added a field called _id to the class. Now the insert doesnt work saying that the _id field cannot be null. A tried BsonIgnoreIfNull attribute, that didnt work.

Teoman Soygul
  • 25,584
  • 6
  • 69
  • 80
pm100
  • 48,078
  • 23
  • 82
  • 145

7 Answers7

75

When you insert an object, if it doesn't have an _id field then the driver adds one and sets it to a 12-byte MongoDB ObjectId value.

You just need to add an Id property to your POCO, which will be deserialised from _id:

public class Thingy
{
     public ObjectId Id { get; set; }
}

Or, if you'd like to delegate another property to map onto _id then you can decorate it with the BsonIdAttribute, like this:

[BsonId]
public ObjectId MyKey { get; set; }   

The _id field doesn't have to be an MongoDB ObjectId, you can set it to any value of any data type (except an array), it just needs to be unique within the collection.

Chris Fulstow
  • 41,170
  • 10
  • 86
  • 110
  • 6
    +1 for the final explanation that the _id can be set to any value of any data type (except array). I was a bit confused by the official documentation on this point – s0nica Aug 13 '12 at 13:08
  • 2
    [explitive] [explitive] [explitive], been fighting with this for 2 days. thanks @Chris Fulstow, such an obscure but key feature! – johnny g Nov 20 '15 at 17:02
  • 2
    Emphasis on _The _id field doesn't have to be an MongoDB ObjectId_. If you are using ObjectId or Bson attributes then your object is no longer POCO (plain old CLR object), so really, that's the answer. Avoid using them if you can. – Chad Hedgcock Sep 04 '18 at 14:10
  • @ChadHedgcock i follow you here. But If i dont have any property on my poco class that corresponds to this I get an error while loading the document. like " _id couldt map to anything" – Jepzen Nov 21 '18 at 12:38
  • 1
    @Jepzen bit late to game but the class attribute [BsonIgnoreExtraElements] might fix that issue. – Chris Christopher Mar 16 '20 at 20:28
11

You have to add a property (or field) for id and tell serializer which id generator you'd like to use.

[BsonId(IdGenerator = typeof(ObjectIdGenerator))]
public object ThingyId { get; set; }

There are 3 available in MongoDb Driver or you can write your own. More info at http://www.mongodb.org/display/DOCS/CSharp+Driver+Serialization+Tutorial#CSharpDriverSerializationTutorial-WriteacustomIdgenerator

Wojtek
  • 111
  • 2
5

I generally wrap Thingy:

public class MongoThingy
{
    public ObjectId Id { get; set; }
    public Thingy Thingy { get; set; }
}

It makes it a lot easier, as often times class Thingy comes from a different library over which I have no control. It's also easier to deserialize in order to hand it over to someone else for processsing.

Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
Ravi J
  • 61
  • 1
  • 4
2
public class Thingy
{
      public ObjectId Id { get; set; }
      public string Foo { get; set; }
}

According to class

Where needed, use the following code:

var collection = database.GetCollection<Thingy>("db_Thingy");
Thingy tg= new Thingy();
tg.Foo = "Hello";
collection.insert(tg);
Amirali Eshghi
  • 963
  • 1
  • 14
  • 21
2

Add a property as follows:

public BsonObjectId Id { get; set; }

The MongoDB driver automatically converts Id to _id during serialization\deserializtion.

Bryan Migliorisi
  • 8,982
  • 4
  • 34
  • 47
  • thx - I have a feeling that there is a set of docs, samples or something that I am missing :-) – pm100 May 19 '11 at 20:06
  • 1
    @Bryan Migliorisi - this doesnt work. THe insert (or Save) fails telling me that Id cannot be null – pm100 May 19 '11 at 20:29
  • @Bryan Migliorisi - official c# driver from mongodb git site, downloaded yesterday – pm100 May 19 '11 at 22:01
  • The data type of the Id property should be ObjectId, not BsonObjectId. Although BsonObjectId seems reasonable also, so I'll create JIRA request to support it as well. – Robert Stam May 20 '11 at 16:18
  • Interesting... Robert, I've used BsonObjectId for every entity in my code without any problems using your driver. – Bryan Migliorisi May 20 '11 at 20:37
  • i had it as BsonObjectID - which explains it – pm100 May 20 '11 at 22:33
  • As long as you assigned a value to the BsonObjectId everything was fine. It was only when you left it null and called Save expecting to autogenerate a unique value for it that there was a problem. – Robert Stam May 24 '11 at 15:48
  • This JIRA has now been implemented: jira.mongodb.org/browse/CSHARP-231. I still recommend that you use ObjectId as the data type of your Id property, but if for some reason you prefer BsonObjectId it is now fully supported. – Robert Stam May 24 '11 at 15:49
  • Does ObjectId automatically create a BsonObjectId value? I've been instantiating the object in my constructors. – Bryan Migliorisi May 25 '11 at 00:28
  • There's some information about the difference between ObjectId and BsonObjectId at http://www.mongodb.org/display/DOCS/CSharp+Driver+Tutorial#CSharpDriverTutorial-ObjectIdandBsonObjectId. In general, if you are working with BsonDocuments you will be using BsonObjectIds, and if you are working with C# POCOs you will be using ObjectId (although since there is an automatic conversion from ObjectId to BsonObjectId you can also use ObjectIds with BsonDocuments). – Robert Stam May 25 '11 at 22:18
0

The way by https://learn.microsoft.com/pt-br/aspnet/core/tutorials/first-mongo-app?view=aspnetcore-5.0&tabs=visual-studio

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;

namespace BooksApi.Models
{
    public class Book
    {
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]
        public string Id { get; set; }

        [BsonElement("Name")]
        public string BookName { get; set; }

        (...)
    }
}
SantanaFire
  • 101
  • 3
0

As suggested by Chris Christopher in a comment above, you can use BsonIgnoreExtraElements class attribute:

[BsonIgnoreExtraElements]
public class Thingy
{
     public string Foo { get; set; }
}

This way you don't have to add an Id property with some other BSon attribute.

ilForna
  • 41
  • 1
  • 4