在MongoDb中为现有字典添加一个关键字,同时使用C#替换其他字段



我想通过修改文档中字典的新值来更新现有文档,同时替换其他字段。我们可以将其视为更改当前地址,同时保留以前的行踪列表。

构成信息的类如下所示。

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);

看看这篇文章,可以找到运行类似高级查询的替代解决方案。

相关内容