我想通过修改文档中字典的新值来更新现有文档,同时替换其他字段。我们可以将其视为更改当前地址,同时保留以前的行踪列表。
构成信息的类如下所示。
class Thing
{
public string Name { get; set; }
public string Location { get; set; }
public Dictionary<string, string> History { get; set; }
}
我正在使用以下代码进行更新。
Thing update = ...;
Thing output = await _dbContext.Things
.FindOneAndUpdateAsync(
Builders<Thing>.Filter.Where(a => a.Name == update.name),
Builders<Thing>.Update.Set(
b => b,
update
), ...
);
显然,我需要向DB解释应该如何进行更新:将Location
的当前值添加到History
,例如时间戳或索引作为键(。谷歌给了我一个博客,建议在ReturnDocument
上这样做。
Thing output = await _dbContext.Things
.FindOneAndUpdateAsync(
Builders<Thing>.Filter.Where(a => a.Name == update.name),
Builders<Thing>.Update.Set(
b => b,
update
),
new FindOneAndUpdateOptions<Thing>
{
ReturnDocument = ReturnDocument.Before
}, ...
);
现在,我想(虽然不确定(我应该将当前值添加到历史中。但是,我甚至无法尝试,因为我无法访问文档的Thing
类型的内容。我只能获得一个BSON对象,这给了我很少的东西。我也找到了这个答案,但它替换了字典中一个键的当前值,而不是修改一个附加值(此外,如果lambda表达式是一个可行的选项,我对它有点偏好(。通常对官方文件的检查只会导致更多的混乱。下面的伪代码显示了我试图达到的目标
...,
Builders<Thing>.Update.Set(
b => b,
new Thing
{
Name = b.name,
Location = update.location,
History = History.Add(DateTime.Now, b.Location)
}
), ...
我该怎么做?
首先,您需要将字典键/值对存储为数据库中的文档数组,并具有以下属性:
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)]
public Dictionary<string, string> History { get; set; }
然后您需要运行一个聚合管道更新,类似于以下查询:
db.Thing.updateOne(
{ Name: "NAME" },
[
{
$set: { Location: "NEW LOC" }
},
{
$set: {
History: {
$concatArrays: [
"$History",
[{ k: "NEW DATE", v: "$Location" }]
]
}
}
}
])
不幸的是,c驱动程序没有对管道更新的强类型支持,也没有像$concatArray这样的运算符。所以你将不得不求助于一个基于字符串的解决方案,比如:
var filter = Builders<Thing>.Filter.Where(t => t.Name == "NAME");
var pipeline = PipelineDefinition<Thing, Thing>.Create(@"
{
$set: {
History: {
$concatArrays: [
'$History',
[{ k: 'NEW DATE', v: '$Location' }]
]
}
}
}");
await collection.UpdateOneAsync(filter, pipeline);
看看这篇文章,可以找到运行类似高级查询的替代解决方案。