mongdb обеспечивает уникальность на двух полях в обе стороны - PullRequest
0 голосов
/ 18 октября 2018

Скажите, у меня есть поля a и b.Я хочу иметь сложную уникальность, в которой, если a: 1, b: 2, я не смогу сделать a: 2, b: 1.

. Причина, по которой я этого хочу, заключается в том, что я делаю коллекцию «список друзей»,где, если a подключен к b, то это также автоматически и наоборот.

возможно ли это на уровне схемы или мне нужно выполнить запросы для проверки.

Ответы [ 2 ]

0 голосов
/ 18 октября 2018

Если вам не нужно различать запрашивающего и запрашиваемого, вы можете отсортировать значения перед сохранением или запросом, чтобы ваши два поля a и b имели предсказуемый порядок для любой пары идентификаторов друзей (и выможет использовать уникальное ограничение индекса).

Например, используя оболочку mongo:

  • Создать вспомогательную функцию для возврата пар друзей в предсказуемом порядке:

    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 }
    
  • Вместо обработки повторяющихся ошибок ключа или вставки вместо обновления можно также использовать findAndModify с upsert, поскольку ожидается, что это будет уникальная пара:

    > 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"
    }
    
0 голосов
/ 18 октября 2018

Не похоже, что вы можете сделать уникальные значения для всего массива, поэтому я делаю некоторую работу вокруг.Я использую $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 ] } } )
...