Issue with MongoDB C# Driver: $set statement not recognizing query operation

I am facing a problem. Using the database myDb and the collection myCollection I inserted the document below

{
  "_id": 1,
  "status": 1,
  "arrayField": [
    {
      "A": 1,
      "B": 1
    }
  ]
}

I am executing the code in C# to update the status if the status is equal to 1 otherwise, it should remain the same. I am using the code below

var update = new BsonDocument()
{
    ["$set"] = new BsonDocument()
    {
        ["status"] = new BsonDocument()
        {
            ["$cond"] = new BsonDocument()
            {
                ["if"] = new BsonDocument()
                {
                    ["$eq"] = new BsonArray() { "$status", 1 }
                },
                ["then"] = 30,
                ["else"] = "$status"
            }
        }
    }
};


var filter = Builders<BsonDocument>.Filter.Eq("_id", 1);


collection.FindOneAndUpdate(filter, update, new FindOneAndUpdateOptions<BsonDocument, BsonDocument>()
{
    ReturnDocument = ReturnDocument.After
});

When I execute this code, instead my code being like:

{
  "_id": 1,
  "status": 30,
  "arrayField": [
    {
      "A": 1,
      "B": 1
    }
  ]
}

It is like:

{
  "_id": 1,
  "status": {
    "$cond": {
      "if": {
        "$eq": [
          "$status",
          1
        ]
      },
      "then": 30,
      "else": "$status"
    }
  },
  "arrayField": [
    {
      "A": 1,
      "B": 1
    }
  ]
}

For some reason that i don’t understand, the MongoDB driver is not recognizing the query operation inside the $set statement and is setting the query as the raw value.

Hi, @Ryan_Brocco,

Welcome to the MongoDB Community Forums. I understand that you are seeing unexpected behaviour when executing a FindOneAndUpdate operation. The root cause is that the update parameter is a BsonDocument rather than a PipelineDefinition.

A BsonDocument says match this document and set the field (status) to the value ($cond document). A PipelineDefinition says run this aggregation pipeline to set the values for the matched document.

Here’s an example of how you can perform the desired update using the .NET/C# Driver.

var update = new [] {
new BsonDocument
{
    ["$set"] = new BsonDocument()
    {
        ["status"] = new BsonDocument()
        {
            ["$cond"] = new BsonDocument()
            {
                ["if"] = new BsonDocument()
                {
                    ["$eq"] = new BsonArray() { "$status", 1 }
                },
                ["then"] = 30,
                ["else"] = "$status"
            }
        }
    }
}};

var pipeline = PipelineDefinition<BsonDocument, BsonDocument>.Create(update);

var filter = Builders<BsonDocument>.Filter.Eq("_id", 1);

var after = coll.FindOneAndUpdate(filter, pipeline, new FindOneAndUpdateOptions<BsonDocument, BsonDocument>()
{
    ReturnDocument = ReturnDocument.After
});

Hope this helps.

Sincerely,
James

1 Like

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