2

I'm trying to update the data type of a field from string to ObjectId for all documents in a collection using MongoDB C# driver. This query works perfectly fine:

db.getCollection('MyCollection').updateMany(
    { MyField: { $type: 2 } },
    [{ $set: { MyField: { $toObjectId: "$MyField" } } }]
);

But I'm struggling to write the same query in C#. I've tried the following query using UpdateManyAsync:

var filter = new BsonDocument("MyField", new BsonDocument("$type", BsonType.String));
                var update = new BsonDocument {
                    { "$set", new BsonDocument("MyField", new BsonDocument("$toObjectId", "$MyField")) }
                };
var updateResult = await collection.UpdateManyAsync(filter, update);

But got the following error:

The dollar ($) prefixed field '$toObjectId' in 'MyField.$toObjectId' is not valid for storage

This example here works, but it's not ideal because it forces me to fetch all documents:

var updateList = new List<WriteModel<BsonDocument>>();
var documents = await collection.Find(Builders<BsonDocument>.Filter.Empty).ToListAsync();

foreach (var document in documents)
{
    var id = document.GetElement("_id").Value.AsString;
    var myFieldValue = document.GetElement("MyField").Value.AsString;

    var filter = Builders<BsonDocument>.Filter.Eq("_id", id);
    var update = Builders<BsonDocument>.Update.Set("MyField", new BsonObjectId(ObjectId.Parse(myFieldValue)));
    updateList.Add(new UpdateOneModel<BsonDocument>(filter, update));
}

if (updateList.Any())
{
    var bulkWriteResult = await collection.BulkWriteAsync(updateList);          
}
10
  • As understand from the first code and second. You have $toObjectId in first one and $toString in the next one. Maybe it causes an error? Commented Dec 29, 2021 at 15:54
  • Oops, that is a typo. I'm going to edit the question to fix that. Commented Dec 29, 2021 at 16:01
  • Done, fixed the code examples. Sorry for that Commented Dec 29, 2021 at 16:04
  • 1
    Found some info, could be helpful actually. mongodb.com/community/forums/t/… Commented Dec 29, 2021 at 17:28
  • 1
    Thank you @kanils_! You pointed me in the right direction! Check my answer below, please. :) Commented Dec 29, 2021 at 18:00

2 Answers 2

2

Check this:

        var pipeline = Builders<BsonDocument>
            .Update
            .Pipeline(new EmptyPipelineDefinition<BsonDocument>()
                .AppendStage<BsonDocument, BsonDocument, BsonDocument>("{ $set: { MyField: { $toObjectId: '$MyField' } } }"));
        coll.UpdateMany(
            new BsonDocument("MyField", new BsonDocument("$type", BsonType.String)),
            pipeline);
Sign up to request clarification or add additional context in comments.

Comments

1

This code example works:

var filter = new BsonDocument("MyField", new BsonDocument("$type", BsonType.String));
var stage = new BsonDocument { { "$set", new BsonDocument { { "MyField", new BsonDocument { { "$toObjectId", "$MyField" } } } } } };
var pipeline = PipelineDefinition<BsonDocument, BsonDocument>.Create(stage);
var update = Builders<BsonDocument>.Update.Pipeline(pipeline);

var result = await collection.UpdateManyAsync(filter, update);

Many thanks @kanils_ you pointed me in the right direction, this example Mongo Db driver C# aggregation for update also helped me to write the code above. Also many thanks @dododo for your suggestion.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.