35

I have inserted documents into MongoDB without an id. And I want to retrieve them by searching through their MongoDB ObjectId, that has been assigned in default.

Here is my attempt-

var query_id = Query.EQ("_id", "50ed4e7d5baffd13a44d0153");
var entity = dbCollection.FindOne(query_id);
return entity.ToString();

And I get following error-

A first chance exception of type 'System.NullReferenceException' occurred

What is the problem?

Minhas Kamal
  • 20,752
  • 7
  • 62
  • 64
Mike Barnes
  • 4,217
  • 18
  • 40
  • 64

5 Answers5

67

You need to create an instance of ObjectId and then query using that instance, otherwise your query compares ObjectIds to string and fails to find matching documents.

This should work:

var query_id = Query.EQ("_id", ObjectId.Parse("50ed4e7d5baffd13a44d0153"));
var entity = dbCollection.FindOne(query_id);
return entity.ToString();
soulcheck
  • 36,297
  • 6
  • 91
  • 90
  • 4
    This answer is nearly correct. At least in C#, it appears that there is no longer a FindOne() method. Replace it with FindOneAs() instead. Here's a link to a good example, this one uses FindAs(), but it's the same principle: http://stackoverflow.com/a/12345580/2705003 – kbpontius Mar 23 '15 at 14:59
  • 4
    There is now no longer a FineAs or FindOneAs method, Minhas Kamal answer should be referenced instead – Brian Ogden Sep 11 '17 at 19:17
  • As soul-check mentions. The _id field is NOT a string, but a more complex datatype called ObjectId. – FlyingV Nov 03 '19 at 06:55
37

In C# for latest official MongoDB.Driver write this-

var filter_id = Builders<MODEL_NAME>.Filter.Eq("id", ObjectId.Parse("50ed4e7d5baffd13a44d0153"));
var entity = dbCollection.Find(filter).FirstOrDefault();
return entity.ToString();

We can accomplish the same result without converting id from string to ObjectId. But then, we will have to add [BsonRepresentation(BsonType.ObjectId)] before id attribute in the model class.

The code can even be further simplified using lambda expression-

var entity = dbCollection.Find(document => document.id == "50ed4e7d5baffd13a44d0153").FirstOrDefault();
return entity.ToString();
Minhas Kamal
  • 20,752
  • 7
  • 62
  • 64
  • Upon `ObjectId.Parse(cool_id.ToString())` I continually get that the guid is "not a valid 24 digit hex string" - what an I doing wrong? – Vincent Buscarello Jul 19 '18 at 00:48
  • @VincentBuscarello, as it says, your cool_id has not valid string representation. Might be use of ObjectId.TryParse(cool_id.ToString(), out ObjectId parsedResult) instead? – Sergei Kovalenko Aug 16 '19 at 13:42
  • @minhas-kamal can you help me on my query above soln not works in my case https://stackoverflow.com/questions/74835380/how-to-do-a-partial-search-of-mongdb-object-id-in-c-sharp – Mohamed Sahir Dec 17 '22 at 15:51
4

If you're here in 2018 and want copy/paste code that still works or pure string syntax;

    [Fact]
    public async Task QueryUsingObjectId()
    {
        var filter = Builders<CosmosParkingFactory>.Filter.Eq("_id", new ObjectId("5b57516fd16cb04bfc35fcc6"));
        var entity = stocksCollection.Find(filter);
        var stock = await entity.SingleOrDefaultAsync();
        Assert.NotNull(stock);

        var idString = "5b57516fd16cb04bfc35fcc6";
        var stringFilter = "{ _id: ObjectId('" + idString + "') }";
        var entityStringFiltered = stocksCollection.Find(stringFilter);
        var stockStringFiltered = await entityStringFiltered.SingleOrDefaultAsync();
        Assert.NotNull(stockStringFiltered);
    }
Kdog
  • 286
  • 3
  • 13
3

The selected answer is correct. For anyone confused by the Query.EQ, here is another way to write a basic update (updates the entire mongodb document):

string mongoDocumentID = "123455666767778";
var query = new QueryDocument("_id", ObjectId.Parse(mongoDocumentID)); 
var update = new UpdateDocument { { "$set", documentToSave } };
mongoCollection.Update(query, update, UpdateFlags.Multi);

The ObjectId object is needed when you want to actually search by object ID, otherwise it is comparing string to objectid type, and it won't match. Mongo is very type-strict in this way, regardless if the field name is correct.

smakus
  • 1,107
  • 10
  • 11
0

You can also do it this way, its

public static ObjectId GetInternalId(string id)
    {
        if (!ObjectId.TryParse(id, out ObjectId internalId))
            internalId = ObjectId.Empty;

        return internalId;
    }

then in your method you can do something like this

ObjectId internalId = GetMongoId.GetInternalId(id);
        return await YourContext.YourTable.Find(c => c.InternalId == internalId).FirstOrDefaultAsync();

Note: id param in GetInternalId its a parameter on that method. In case you need as this:

public async Task<YourTable> Find(string id)
    {
        ObjectId internalId = GetMongoId.GetInternalId(id);
        return await YourContext.YourTable.Find(c => c.InternalId == internalId).FirstOrDefaultAsync();
    }

Hope it helps also.

Raul Baez
  • 1
  • 1