$ AddToSet到Dictionary(MongoDB,C#)重复条目

时间:2013-10-15 10:31:23

标签: c# mongodb mongodb-.net-driver mongodb-query

我有一个MongoDB集合(“Users”),它包含一个字典字段(“UserRegistrations”)。

字段定义是:

    BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)]
    public Dictionary<string, UserRegistration> UserRegistrations = new Dictionary<string, UserRegistration>();

这是一个字典,由一个键(String)和一个自定义对象组成。

这是它在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);

它不会检查是否存在相同的密钥,导致Dictionary字段中的重复,这会导致MongoDB C#驱动程序中的反序列化错误。

如何确保相同的密钥不存在?

谢谢!

2 个答案:

答案 0 :(得分:1)

在架构的当前状态下,我认为只使用mongodb的一个更新查询就可以实现您的尝试。

你有两个选择(也许还有更多我没有想到的)

<强> 1。编辑程序中的文档

不是仅使用您要附加的键值更新文档,而是

  • 在数据库中查询整个文档,
  • 将其放入本地C#TDocument对象
  • 将您的键值对附加到文档的本地副本上,确保您不添加已存在的键并且
  • 使用Save document方法将其更新到数据库中。

此方法非常慢(与直接更新相比),但它是在不更改架构的情况下执行所要求的唯一方法。

<强> 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",
  }
}

Pro:您不再需要担心每个文档的16MB限制,并且每个用户可以拥有几乎无限的“UserRegistrations”(无论它们是什么)。

Con:您必须执行可能使用索引快速的连接,但在使用mongodb时,您应该尽量避免使用它们。

这只是我提出的问题的快速解决方案。如果您有兴趣,应该研究如何构建模式。 MongoDb data modelling manualthis question可以帮助您入门。

答案 1 :(得分:0)

感谢您的回答,但这不是我想要的。

将集合分离到另一个“UserRegistrations”集合是计数器NoSQL方法,后来需要昂贵的索引。我不需要16mb,实际上大约1mb就足够了所以这对我来说不是一个专业人士。

我需要一个NoSQL,比如o(1)通过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尽快添加此功能。