简体   繁体   中英

How to use formula (or Expression) to update value using Mongo DB C# Drivers 4.2?

I am quite new to MongoDb (and MongoDb C# Drivers) and lately, we are trying to implement an update wherein we use the value of a field and a variable (method parameter) to update several fields.

Basically, our doc is something like this

public class Inventory {

public string _id;

public decimal Quantity;

public decimal TotalCost;

}

What we want to do is to update the quantity and totalCost based on a passed value (qty).

(1) TotalCost -= (qty * (TotalCost / Quantity))

(2) Quantity -= Qty

The logic behind this is that we want to retain the average cost of our item. Take note: the value of quantity field in step (1) should use the original value and not the result of step (2).

We can implement this using 2 queries but in our case, we need to execute this logic in one call only as there are different threads that will update a single item.

I have read the docs about Aggregate and Projection (and using Expressions) but I cannot seem to figure out how to use or combine the result of projection into the aggregate update.

Tried this projection to return the value that should be deducted from totalCost

Builders.Projection.Expression(e => (e.totalCost / e.quantity) * -qty);

Thank you and hope you guys can point us in the right direction.

Here is an equivalent of what we are trying to achieve in mongo shell, provided that qty = 500.

db.inventory.updateOne( { _id: "1" }, [ { "$set": { "TotalCost": { "$add": ["$TotalCost", { "$multiply": [-500, { "$divide": ["$TotalCost", "$Quantity"] }] }] } } } ] )

There's currently no type-safe helper methods for creating update pipelines. However, you can just use the same json-ish syntax like you do with the console. Here's bit of example C# code.

// Some id to filter on
var id = ObjectId.GenerateNewId();


var db = client.GetDatabase("test");
var inventory = db.GetCollection<Inventory>("inventory");


var filter = Builders<Inventory>.Filter
    .In(x => x.Id, id);

var update = Builders<Inventory>.Update.Pipeline(
    new PipelineStagePipelineDefinition<Inventory, Inventory>(
        new PipelineStageDefinition<Inventory, Inventory>[]
        {
            @"{ ""$set"": { ""TotalCost"": { ""$add"": [""$TotalCost"", { ""$multiply"": [-500, { ""$divide"": [""$TotalCost"", ""$Quantity""] }] }] } } }",
        }));

await inventory.UpdateOneAsync(filter, update)
    .ConfigureAwait(false);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM