Home > Software design >  Update data type of field for all document using MongoDB C# driver
Update data type of field for all document using MongoDB C# driver

Time:12-30

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);          
}

CodePudding user response:

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);

CodePudding user response:

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.

  • Related