C# MongoDB Driver:如何使用UpdateDefinitionBuilder动态构建更新查询?
Hey, I get what you're trying to do here—building a dynamic MongoDB update query based on conditions. The issue with your current approach is that each Set() call on Builders<Product>.Update returns a new UpdateDefinition<Product> instance (they're immutable), so your current code isn't actually accumulating all those updates. The conditional Set() calls won't stick because you're not saving their result back to the update variable, and only the final Set() would take effect otherwise.
Here are two solid approaches to fix this:
Approach 1: Accumulate Updates by Reassigning the Variable
This is the most straightforward method for simple conditional updates. You start with an initial update, then reassign the update variable each time you add a new operation:
// Start with your base update operation var update = Builders<Product>.Update.Set(p => p.PropertyA, "A update"); // Add conditional X/Y update if (someConditionX) { update = update.Set(p => p.PropertyX, "X update"); } else { update = update.Set(p => p.PropertyY, "Y update"); } // Add the B update update = update.Set(p => p.PropertyB, "B update"); // Add conditional Z/P update if (someConditionZ) { update = update.Set(p => p.PropertyZ, "Z update"); } else { update = update.Set(p => p.PropertyP, "P update"); } // Execute the update await collection.UpdateOneAsync(filter, update, updateOptions);
Each time you call update.Set(...), you're creating a new combined update definition and saving it back to the update variable—this way, all operations are accumulated correctly.
Approach 2: Collect Operations in a List and Combine
If you have a lot of dynamic operations (or mix different types like Set, Inc, Push), collecting all update operations in a list and then combining them is cleaner:
var updateOperations = new List<UpdateDefinition<Product>>(); // Add base operations updateOperations.Add(Builders<Product>.Update.Set(p => p.PropertyA, "A update")); updateOperations.Add(Builders<Product>.Update.Set(p => p.PropertyB, "B update")); // Add conditional X/Y operation if (someConditionX) { updateOperations.Add(Builders<Product>.Update.Set(p => p.PropertyX, "X update")); } else { updateOperations.Add(Builders<Product>.Update.Set(p => p.PropertyY, "Y update")); } // Add conditional Z/P operation if (someConditionZ) { updateOperations.Add(Builders<Product>.Update.Set(p => p.PropertyZ, "Z update")); } else { updateOperations.Add(Builders<Product>.Update.Set(p => p.PropertyP, "P update")); } // Combine all operations into a single UpdateDefinition var update = Builders<Product>.Update.Combine(updateOperations); // Execute the update await collection.UpdateOneAsync(filter, update, updateOptions);
This method keeps your code organized, especially if you need to add or remove operations dynamically based on complex logic.
A quick note: Always use strongly-typed expressions (like p => p.PropertyA) instead of string literals when possible—it avoids typos and gives you compile-time checks.
内容的提问来源于stack exchange,提问作者Liran Friedman

