C# MongoDb C在数组元素处更新元素
我的文件结构如下:C# MongoDb C在数组元素处更新元素,c#,mongodb,asp.net-web-api,.net-core,C#,Mongodb,Asp.net Web Api,.net Core,我的文件结构如下: { "name":"Test Online", "strategies":[ { "strategyType":"Online", "strategyBudget":0, "extraElements":{ "URL":"http:\\www.google.com" } }, { "strategyType":"TV
{
"name":"Test Online",
"strategies":[
{
"strategyType":"Online",
"strategyBudget":0,
"extraElements":{
"URL":"http:\\www.google.com"
}
},
{
"strategyType":"TV",
"strategyBudget":0,
"extraElements":{
"ChannelSlots":[
{
"channelName":"SIC",
"fromHour":"13:30:00",
"toHour":"13:30:00"
},
{
"channelName":"TVI",
"fromHour":"15:30:00",
"toHour":"16:30:00"
}
]
}
},
{
"strategyType":"Outdoor",
"strategyBudget":2000,
"extraElements":{
"Latitude": 8.123456,
"Longitude": -16.123456
}
}
],
"campaignBudget":3000
}
我想创建一个函数来收集活动预算,将其平均分配给案例3中定义的所有策略,然后为每个策略更新strategyBudget字段
我已经创建了所有必要的对象,以便以类型安全的方式执行此操作。例如,我对战略有如下建议:
[BsonDiscriminator("StrategyType", RootClass = true, Required = true)]
[BsonKnownTypes(
typeof(OnlineStrategy),
typeof(TvStrategy),
typeof(OutdoorStrategy))]
public class Strategy
{
[JsonConverter(typeof(StringEnumConverter))] // JSON.Net
[BsonRepresentation(BsonType.String)] // Mongo
public StrategyType StrategyType { get; set; }
[JsonProperty("strategyBudget")]
public int StrategyBudget { get; set; }
[JsonProperty("extraElements")]
public ExtraElements ExtraElements { get; set; }
}
}
所以我可以打电话给Strategy.StrategyBudget,然后我得到或设定预算
到目前为止,我的职能是:
/**
* Divide the budget of a campaign equally between all defined strategies for that campaign
* so if a campaign has 3000 of budget and 3 strategies,
* each strategy would get 1000, and the campaign budget is set to 0
*/
private void DivideBudgetEqually(string campaignID)
{
Campaign campaignRecord = _campaigns.Find(cpg => cpg.Id == campaignID).FirstOrDefault();
int campaignBudget = campaignRecord.CampaignBudget;
int numStrategies = campaignRecord.Strategies.Count;
int equalBudget = campaignBudget / numStrategies;
var campaignFilter = Builders<Campaign>.Filter.Eq(cpg => cpg.Id, campaignID);
var strategyUpdate = Builders<Campaign>.Update.Set(cpg => cpg.Strategies[-1].StrategyBudget, equalBudget);
var campaignUpdate = Builders<Campaign>.Update.Set(cpg => cpg.CampaignBudget, 0);
// update the each strategy budget to equal value
var resultStrategy = _campaigns.UpdateMany(campaignFilter, strategyUpdate);
// update the campaign budget to 0, since we've distributed all the budget to the strategies
var resultCampaign = _campaigns.UpdateMany(campaignFilter, campaignUpdate);
}
但当我调用端点来执行此操作时,我得到以下结果:
web_1 | fail: Microsoft.AspNetCore.Server.Kestrel[13]
web_1 | Connection id "0HLVNUBP8QGRB", Request id "0HLVNUBP8QGRB:00000001": An unhandled exception was thrown by the application.
web_1 | MongoDB.Driver.MongoWriteException: A write operation resulted in an error.
web_1 | The positional operator did not find the match needed from the query.
web_1 | ---> MongoDB.Driver.MongoBulkWriteException`1[semasio_challenge_2.Models.Campaign]: A bulk write operation resulted in one or more errors.
web_1 | The positional operator did not find the match needed from the query.
web_1 | at MongoDB.Driver.MongoCollectionImpl`1.BulkWrite(IClientSessionHandle session, IEnumerable`1 requests, BulkWriteOptions options, CancellationToken cancellationToken)
web_1 | at MongoDB.Driver.MongoCollectionImpl`1.<>c__DisplayClass23_0.<BulkWrite>b__0(IClientSessionHandle session)
web_1 | at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSession[TResult](Func`2 func, CancellationToken cancellationToken)
web_1 | at MongoDB.Driver.MongoCollectionImpl`1.BulkWrite(IEnumerable`1 requests, BulkWriteOptions options, CancellationToken cancellationToken)
web_1 | at MongoDB.Driver.MongoCollectionBase`1.<>c__DisplayClass92_0.<UpdateMany>b__0(IEnumerable`1 requests, BulkWriteOptions bulkWriteOptions)
web_1 | at MongoDB.Driver.MongoCollectionBase`1.UpdateMany(FilterDefinition`1 filter, UpdateDefinition`1 update, UpdateOptions options, Func`3 bulkWrite)
web_1 | --- End of inner exception stack trace ---
web_1 | at MongoDB.Driver.MongoCollectionBase`1.UpdateMany(FilterDefinition`1 filter, UpdateDefinition`1 update, UpdateOptions options, Func`3 bulkWrite)
web_1 | at MongoDB.Driver.MongoCollectionBase`1.UpdateMany(FilterDefinition`1 filter, UpdateDefinition`1 update, UpdateOptions options, CancellationToken cancellationToken)
web_1 | at semasio_challenge_2.Services.CampaignService.DivideBudgetEqually(String campaignID) in /src/Services/CampaignService.cs:line 109
如果我将更新函数更改为任何异步版本,则不会发生此错误,但不会更新startegyBudget,但会更新campaign one
我在这里做错了什么?您的活动筛选器需要匹配数组中要使用位置运算符$更新的一个文档
这:
var-activityfilter=Builders.Filter.Eqcpg=>cpg.Id,activityid;
需要更改为以下内容:
var-activityfilter=Builders.Filter.Eqcpg=>cpg.Id,activityid
&Builders.Filter.ElemMatchcpg=>cpg.Strategies,x=>x.FieldToMatch==test;
作为参考,使用本文中的数组过滤器建议是执行该操作的代码,因为在C中使用数组过滤器的示例很少:
var campaignFilter = Builders<Campaign>.Filter.Eq(cpg => cpg.Id, campaignID);
// mongo c# driver has yet to have a fluent syntax for Array Filters.
var updateDefinition = Builders<Campaign>.Update.Set("Strategies.$[stra].StrategyBudget", equalBudget);
var arrayFilterStratergy = new List<ArrayFilterDefinition>();
arrayFilterStratergy.Add(
new BsonDocumentArrayFilterDefinition<BsonDocument>(new BsonDocument("stra.StrategyBudget", new BsonDocument("$gte", 0)))
);
// update the each strategy budget to equal value
var resultStrategy = await _campaigns.UpdateOneAsync(
campaignFilter,
updateDefinition,
new UpdateOptions { ArrayFilters = arrayFilterStratergy });
这就像一个符咒:var-campaignFilter=Builders.Filter.Eqcpg=>cpg.Id,campaignID&Builders.Filter.ElemMatchcpg=>cpg.Strategies,x=>x.StrategyBudget!=平等预算;嗯,它只是更新了第一个策略。我使用的是UpdateManyAsync。位置运算符将只更新数组中第一个匹配的元素,UpdateMany用于更新多个文档,而不是数组项。如果要对文档中的数组进行更复杂的更新,请查看数组筛选器-