.NET Driver - Update the value of two items in a nested document in one operation

I have a document with the following nested documents in array, each with their own _id.

{
  "_id": {
    "$oid": "65d46f1eaa08d32595abca1a"
  },
  "inventory": [
    {
      "_id": "cash",
      "qty": 100
    },
    {
      "_id": "gold",
      "qty": 0
    }
  ]
}

I want to update both the ‘qty’ values of cash and gold in one update, i.e I want to transfer 100 cash to gold. So the end result will be 0 cash, and 100 gold.

The closest I’ve come is being able to find one element by _id, and update that, but I can’t figure out how to update both elements in the array at once.

var filter = Builders<Player>.Filter
            .Eq(r => r.Id, new ObjectId("65d46f1eaa08d32595abca1a"))
                     & Builders<Player>.Filter.ElemMatch(x => x.Inventory, Builders<PlayerInventoryItem>.Filter.Eq(x => x.Id, "cash"));
        
        var update = Builders<Player>.Update.Set(x => x.Inventory.FirstMatchingElement().Qty, 500);
        
        var updateResult = await _collectionHelper.Players(_mongoClient).UpdateOneAsync(filter, update);

Also if I could do this atomically without any contention from multiple reads/updates causing conflicts that would be great.

Thanks

1 Like

I am pretty sure this is what you want to do

var filter = Builders<Player>.Filter
            .Eq(r => r.Id, new ObjectId("65d46f1eaa08d32595abca1a"))
                     & Builders<Player>.Filter.ElemMatch(x => x.Inventory, Builders<PlayerInventoryItem>.Filter.Eq(x => x.Id, "cash"));
        
var update = Builders<Player>.Update
  // Set gold to 500
  .Set(x => x.Inventory.AllMatchingElements("gold").Qty, 500)
  // Set cash to 0
  .Set(x => x.Inventory.AllMatchingElements("cash").Qty, 0);

var arrayFilters = new[] {
  // match "gold" to anything in the list with the _id "gold"
  new JsonArrayFilterDefinition<Player>($@"{{""gold._id"": {{ $eq: ""gold""}} }}"),
  // match "cash" to anything in the list with the _id "cash"
  new JsonArrayFilterDefinition<Player>($@"{{""cash._id"": {{ $eq: ""cash""}} }}"),
};
        
var updateResult = await _collectionHelper.Players(_mongoClient).UpdateOneAsync(filter, update, new UpdateOptions {
  ArrayFilters = arrayFilters
});

1 Like

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