在使用 C# 替换其他字段的同时向 MongoDb 中的现有字典添加键
Add a key to an existing dictionary in MongoDb while replacing other fields using C#
我想通过修改现有文档中的字典的新值来更新现有文档,同时替换其他字段。我们可以把它看作是改变了当前地址,同时保留了以前行踪的列表。
构成信息的class是这样的
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
), ...
);
显然,我需要向数据库解释应该如何进行更新:将 Location
的当前值添加到 History
,例如时间戳或索引作为键)。谷歌搜索给了我 this blog 建议对 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 对象,这给了我相当少的东西。我还发现 this answer but it replaces the current value of a key in the dictionary instead of amending an additional one (also, I have a slight preference for lambda expressions if such is a viable option). The usual check at the official docs 只会导致更多的混乱。以下伪代码显示了我想要达到的目标。
...,
Builders<Thing>.Update.Set(
b => b,
new Thing
{
Name = b.name,
Location = update.location,
History = History.Add(DateTime.Now, b.Location)
}
), ...
我该怎么办?
首先,您需要将字典 key/value 对存储为数据库中具有以下属性的文档数组:
[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);
查看 this article 以获取针对 运行 像这样的高级查询的替代解决方案。
我想通过修改现有文档中的字典的新值来更新现有文档,同时替换其他字段。我们可以把它看作是改变了当前地址,同时保留了以前行踪的列表。
构成信息的class是这样的
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
), ...
);
显然,我需要向数据库解释应该如何进行更新:将 Location
的当前值添加到 History
,例如时间戳或索引作为键)。谷歌搜索给了我 this blog 建议对 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 对象,这给了我相当少的东西。我还发现 this answer but it replaces the current value of a key in the dictionary instead of amending an additional one (also, I have a slight preference for lambda expressions if such is a viable option). The usual check at the official docs 只会导致更多的混乱。以下伪代码显示了我想要达到的目标。
...,
Builders<Thing>.Update.Set(
b => b,
new Thing
{
Name = b.name,
Location = update.location,
History = History.Add(DateTime.Now, b.Location)
}
), ...
我该怎么办?
首先,您需要将字典 key/value 对存储为数据库中具有以下属性的文档数组:
[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);
查看 this article 以获取针对 运行 像这样的高级查询的替代解决方案。