【问题标题】:mongdb ensure uniqueness on two fields both waysmongodb 双向确保两个字段的唯一性
【发布时间】:2019-03-22 19:35:23
【问题描述】:

假设我有 ab 字段。我想要一个复合唯一性,如果a: 1, b: 2,我将无法做到a: 2, b: 1

我想要这个的原因是因为我正在制作一个“朋友列表”类型的集合,如果 a 连接到 b,那么它也会自动反过来。

这在架构级别上是否可行,还是我需要进行查询才能检查。

【问题讨论】:

  • @AnthonyWinzlet 我实际上想到了另一种可能的方法(我仍在查看是否有任何关于此的文档)。我只需创建一个包含 2 个ObjectIds 的数组:requesterrequestee(顺序无关紧要)。是否可以创建一个索引来确保数组中的所有值都不匹配另一个文档?例如。 [1, 2] 已经插入,[1, 3] 是合法的,但 [2, 1] 不是
  • A.Lau 可能会有另一种方法来做到这一点,但我认为没有比这更好的方法了。并且您可以在该答案中使用 $addToSet 而不是 $push 的独特之处。如果您有任何其他问题,请随时提出。
  • @AnthonyWinzlet $addToSet 实际上只是为了单个文档的唯一性,而不是跨多个文档,也不是顺序。我可能只会使用$all 来确保该组合首先不存在
  • @AnthonyWinzlet 编写了我当前的实现尝试,尽管它不使用唯一索引。

标签: mongodb indexing unique-index


【解决方案1】:

如果您不需要区分请求者和被请求者,您可以在保存或查询之前对值进行排序,以便您的两个字段 ab 对任何一对朋友 ID 具有可预测的顺序(并且您可以利用唯一索引约束)。

例如,使用mongo shell:

  • 创建一个帮助函数以可预测的顺序返回朋友对:

    function friendpair (friend1, friend2) {
        if ( friend1 < friend2) {
            return ({a: friend1, b: friend2})
        } else {
            return ({a: friend2, b: friend1})      
        }
    }
    
  • 添加复合唯一索引:

    > db.friends.createIndex({a:1, b:1}, {unique: true});
    {
        "createdCollectionAutomatically" : true,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
    }
    
  • 插入唯一对(应该可以)

    > db.friends.insert(friendpair(1,2))
    WriteResult({ "nInserted" : 1 })
    
    > db.friends.insert(friendpair(1,3))
    WriteResult({ "nInserted" : 1 })
    
  • 插入非唯一对(应返回重复键错误):

    > db.friends.insert(friendpair(2,1))
    WriteResult({
        "nInserted" : 0,
        "writeError" : {
            "code" : 11000,
            "errmsg" : "E11000 duplicate key error collection: test.friends index: a_1_b_1 dup key: { : 1.0, : 2.0 }"
        }
    })
    
  • 搜索应该以任一顺序工作:

    db.friends.find(friendpair(3,1)).pretty()
    { "_id" : ObjectId("5bc80ed11466009f3b56fa52"), "a" : 1, "b" : 3 }
    
    db.friends.find(friendpair(1,3)).pretty()
    { "_id" : ObjectId("5bc80ed11466009f3b56fa52"), "a" : 1, "b" : 3 }
    
  • 您也可以使用findAndModifyupsert,而不是处理重复的键错误或插入与更新,因为这是一个唯一的对:

    > var pair = friendpair(2,1)
    > db.friends.findAndModify({
        query: pair,
        update: {
            $set: {
                a : pair.a,
                b : pair.b
            },
            $setOnInsert: { status: 'pending' },
        },
        upsert: true
    })
    
    {
        "_id" : ObjectId("5bc81722ce51da0e4118c92f"),
        "a" : 1,
        "b" : 2,
        "status" : "pending"
    }
    

【讨论】:

    【解决方案2】:

    您似乎无法对整个数组的值进行唯一操作,因此我正在做一些工作。我使用$jsonSchema如下:

    {
        $jsonSchema:
            {
                bsonType:
                    "object",
                required:
                    [
                        "status",
                        "users"
                    ],
                properties:
                    {
                        status:
                        {
                            enum:
                            [
                                "pending",
                                "accepted"
                            ],
                            bsonType:
                                "string"
                        },
                        users:
                            {
                                bsonType:
                                    "array",
                                description:
                                    "references two user_id",
                                items:
                                    {
                                        bsonType:
                                            "objectId"
                                    },
                                maxItems: 
                                    2,
                                minItems: 
                                    2,
                            },
                    }
            }
    }
    

    然后我将使用$all 来查找已连接的用户,例如

    db.collection.find( { users: { $all: [ ObjectId1, ObjectId2 ] } } )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-17
      • 1970-01-01
      • 2010-12-10
      相关资源
      最近更新 更多