【问题标题】:$AddToSet to Dictionary (MongoDB, C#) duplicate entries$AddToSet 到 Dictionary (MongoDB, C#) 重复条目
【发布时间】:2013-10-23 02:59:20
【问题描述】:

我有一个 MongoDB 集合(“Users”),其中包含一个字典字段(“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);

它不检查是否已经存在相同的键,导致 Dictionary 字段重复,随后导致 MongoDB C# 驱动程序中的反序列化错误。

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

谢谢!

【问题讨论】:

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


    【解决方案1】:

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

    将集合分离到另一个“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 尽快添加此功能。

    【讨论】:

      【解决方案2】:

      在您的架构的当前状态下,我认为仅使用一个对 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",
        }
      }
      

      专业人士:您不再需要担心每个文档的 16MB 限制,每个用户都可以拥有几乎无限的“用户注册”(无论它们是什么)。

      缺点:您必须执行连接,使用索引可能会很快,但是在使用 mongodb 时,您应该尽量避免它们。

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

      【讨论】:

      • 您好,感谢您的回答,但这不是我想要的。将集合分离到另一个“UserRegistrations”集合是反 NoSQL 方法,稍后将需要昂贵的索引。我不需要 16mb,实际上大约 1mb 就足够了,所以这对我来说不是专业的。在我的应用程序中编辑文档的另一种方法对我来说也不好,这个方法可以异步调用,如果第一次调用获取当前文档,第二次调用也获取它,同时数据会发生冲突。我需要的是一个 MongoDB 解决方案(AddToSet 或类似的)。
      猜你喜欢
      • 2017-05-30
      • 1970-01-01
      • 2015-02-10
      • 2012-08-24
      • 1970-01-01
      • 2020-08-16
      • 2017-01-31
      • 2013-08-26
      相关资源
      最近更新 更多