$AddToSet字典(MongoDB,C#)重复条目
本文关键字:AddToSet 字典 MongoDB | 更新日期: 2023-09-27 18:35:37
我有一个MongoDB集合("用户"),其中包含一个字典字段("UserRegistrations")。
字段定义为:
BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)]
public Dictionary<string, UserRegistration> UserRegistrations = new Dictionary<string, UserRegistration>();
它是一个字典,由一个键(字符串)和一个自定义对象作为值组成。
这是它在MongoDB中反映的方式:
"UserRegistrations" : [{
"k" : "517ba4e1696b03108ccef51a",
"v" : {
"RegistrationDate" : ISODate("2013-07-21T18:57:42.589Z"),
"OtherInfo" : "123456test",
}
}],
当我使用$AddToSet时,如以下示例所示:
IMongoQuery query = Query.EQ("_id", new ObjectId(uid));
var kvp = new KeyValuePair<string, UserRegistration>("517ba4e1696b03108ccef51a", new UserRegistration()
{
RegistrationDate = DateTime.Now.ToUniversalTime(),
});
IMongoUpdate update = Update.AddToSet("UserRegistrations", kvp.ToBsonDocument());
collection.Update(query, update, UpdateFlags.Multi);
它不会检查相同的键是否已存在,从而导致字典字段中出现重复,这稍后会导致MongoDB C#驱动程序中的反序列化错误。
如何确保相同的密钥不存在?
谢谢!
在您的架构的当前状态下,我认为仅使用对 mongodb 的一个更新查询就不可能实现您正在尝试的目标。
你有两个选择(也许还有更多我没有想到的)
1. 编辑程序上的文档
而不仅仅是使用要附加的键值更新文档,
- 查询整个文档的数据库,
- 将其放入本地 C# TDocument 对象中,
- 将您的键值对附加到文档的本地副本上,确保不要添加已经存在的键和
- 使用 Save 文档方法将其更新到数据库中。
此方法非常慢(与直接更新相比),但它是在不更改架构的情况下执行您要求的唯一方法。
2. 更改架构
为每个键值对创建一个单独的集合(名称"UserRegistrations",以便于理解),并且(我猜测包含数组"UserRegistrations"的对象具有一些其他字段,如UserID或类似的东西)创建一个唯一的索引复合索引UserID和键值对中的键。
该集合中的记录如下所示:
{
"UserID" : "unique_user_id_of_user_A"
"k" : "517ba4e1696b03108ccef51a",
"v" : {
"RegistrationDate" : ISODate("2013-07-21T18:57:42.589Z"),
"OtherInfo" : "123456test",
}
}
{
"UserID" : "unique_user_id_of_user_B"
"k" : "jkfadifhafo4ho34fo78h34fo7", #obvious keyboard spazzing here
"v" : {
"RegistrationDate" : ISODate("2013-07-21T19:57:42.589Z"),
"OtherInfo" : "123456test",
}
}
{
"UserID" : "unique_user_id_of_user_A" #same user as first record
"k" : "sfahoihu43o43f7437843f8g348", #different key-value pair
"v" : {
"RegistrationDate" : ISODate("2013-07-22T18:57:42.589Z"),
"OtherInfo" : "123456test",
}
}
优点:您不再需要担心每个文档16MB的限制,每个用户都可以拥有几乎无限的"用户注册"(无论它们是什么)。
缺点:你必须执行使用索引可能很快的加入,但是在使用mongodb时,你应该尽量避免它们。
这只是我想出的问题的快速解决方案。如果你有兴趣,你应该研究如何构建你的模式。MongoDb数据建模手册,这个问题应该让你入门。
感谢您的回答,但这不是我想要的。
将集合分离到另一个"UserRegistrations"集合是反NoSQL方法,以后需要昂贵的索引。我不需要 16mb,实际上大约 1mb 绰绰有余,所以这对我来说不是专业人士。
我需要像o(1)这样的NoSQL通过UID直接访问数据。
在我的应用程序中编辑文档的第二种方法对我也不好,此方法可以异步调用,如果第一次调用获取当前文档,第二次调用获取当前文档,则同时,数据将发生冲突,并且会出现结果未知的竞争条件。
我需要的是一个MongoDB解决方案($AddToSet或类似的单行函数)。
经过一些研究 - 目前,没有MongoDB函数来实现这一点。
无论如何,我最终使用了一个小操作,只需向 Update 语句添加一个限定,该语句首先检查具有此类 ID 的密钥是否已存在。
答:
IMongoQuery query = Query.And("_id", new ObjectId("RootDocumentKey")), Query.NE(string.Format("{0}.k", "FieldName"), BsonValue.Create("DictionaryKey")));
其中"RootDocumentKey","FieldName"和"DictionaryKey"是您的参数。
希望MongoDB能很快添加这个功能。