MongoDB .NET:使用ElemMatch() 替换数组中的字符串
我在使用MongoDb .NET驱动程序(v3.7)来在数组中替换字符串,使用 ElemMatch 来匹配数组中的字符串元素。
我看到的关于 ElemMatch() 的所有示例都涉及在对象数组(或对象列表)中匹配一个对象。
我不能用同样的方法来定位数组中的一个字符串吗?
例如,我想把 round 替换为 triangle,并尝试了下面的代码,认为位置运算符会在需要修改的数组元素中找到/引用该字符串。但也许对原始类型的数组来说,这样做不可行?
var idFilter = Builders<Sample>.Filter.Eq(d => d.Id, "000000000000000000001002");
var elemMatchFilter = Builders<Sample>.Filter.ElemMatch(x => x.MyStringArray, "round");
var filtersAnded = Builders<Sample>.Filter.And(idFilter, elemMatchFilter);
var update = Builders<Sample>.Update.Set("MyStringArray.[$]", "triangle");
//var update = Builders<Sample>.Update.Set("MyStringArray.$", "triangle"); // Tried this but gave same exception
UpdateResult result = collection.UpdateOne(filtersAnded, update);
这会导致一个异常:
JSON reader was expecting a value but found 'round'.
数据模型:
internal class Sample
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; } = ObjectId.GenerateNewId().ToString();
public int[] MyIntArray { get; set; } = [];
public string[] MyStringArray { get; set; } = [];
}
用于生成两个文档的代码:
public const string Samples = "Samples";
IMongoDatabase? iMongoDatabase = mongoClient.GetDatabase("UpdateArraysTesting");
iMongoDatabase.CreateCollection(Samples);
SamplesCollection = iMongoDatabase!.GetCollection<Sample>(Samples);
Sample sample = new() {
Id = "000000000000000000001001",
MyIntArray = new int[] { 10, 15 },
MyStringArray = new string[] {"square","box" }
};
SamplesCollection.InsertOne(sample);
sample = new()
{
Id = "000000000000000000001002",
MyIntArray = new int[] { 22, 27 },
MyStringArray = new string[] { "round", "ball" }
};
SamplesCollection.InsertOne(sample);
更新:为了教我如何使用 ElemMatch(),Aneroid 提供了下面的代码。他为 ElemMatch() 过滤器提供了两个版本,但第一版未能找到匹配项,第二版则成功了。
var idFilter = Builders<Sample>.Filter.Eq(d => d.Id, "000000000000000000001002");
// Version 1 does not find a match
var elemMatchFilter_v1 = Builders<Sample>.Filter.ElemMatch(
x => x.MyStringArray,
Builders<string>.Filter.Eq(s => s, "triangle"));
// Version 2 succeeds in finding a match
var elemMatchFilter_v2 = Builders<Sample>.Filter.ElemMatch(
x => x.MyStringArray,
s => s == "triangle"));
var filtersAnded = Builders<Sample>.Filter.And(idFilter, elemMatchFilter_v2); // elemMatchFilter_v1 does NOT match
var update = Builders<Sample>.Update.Set("MyStringArray.$", "rectangle");
var result = collection.UpdateOne(filtersAnded, update);
以下是从上面代码的 UpdateOne() 调用中捕获的日志输出。
// Version 1 Serilog output
Command started update UpdateArraysTesting { "update" : "Samples", "ordered" : true, "$db" : "UpdateArraysTesting", "lsid" : { "id" : { "$binary" : { "base64" : "i6evdcuCQ+WC3dq0TBO2qw==", "subType" : "04" } } }, "updates" : [{ "q" : { "_id" : { "$oid" : "000000000000000000001002" }, "MyStringArray" : { "$elemMatch" : { "@<current>" : "triangle" } } }, "u" : { "$set" : { "MyStringArray.$" : "rectangle" } } }] }
Command succeeded update UpdateArraysTesting 0.8399 { "n" : 0, "nModified" : 0, "ok" : 1.0 }
// Version 2 Serilog output
Command started update UpdateArraysTesting { "update" : "Samples", "ordered" : true, "$db" : "UpdateArraysTesting", "lsid" : { "id" : { "$binary" : { "base64" : "p9PIap2yRKqvqtBjRKFa+Q==", "subType" : "04" } } }, "updates" : [{ "q" : { "_id" : { "$oid" : "000000000000000000001002" }, "MyStringArray" : { "$elemMatch" : { "$eq" : "triangle" } } }, "u" : { "$set" : { "MyStringArray.$" : "rectangle" } } }] }
Command succeeded update UpdateArraysTesting 0.7627 { "n" : 1, "nModified" : 1, "ok" : 1.0 }
解决方案
elemMatch 在这里并不需要。你可以使用 $ 的位置更新运算符 来更新该数组的值。
位置更新运算符
$在更新查询文档的第一个匹配项处充当占位符。
db.collection.update(
{
_id: "000000000000000000001002",
MyStringArray: "round"
},
{
$set: { "MyStringArray.$": "triangle" }
}
)
在.NET代码中,可能是:
var idFilter = Builders<Sample>.Filter.Eq(d => d.Id, "000000000000000000001002");
var elemFilter = Builders<Sample>.Filter.Eq(x => x.MyStringArray, "round");
// may need AnyEq instead of Eq above
var filtersAnded = Builders<Sample>.Filter.And(idFilter, elemFilter);
var update = Builders<Sample>.Update.Set("MyStringArray.$", "triangle");
UpdateResult result = collection.UpdateOne(filtersAnded, update);
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。