MongoDB — условные ограничения уникальности для разных полей «id»

У меня есть требование обеспечить уникальность документов в коллекции MongoDB.

В моих документах есть поле «id», поле «имя», а также несколько других полей. Поле «id» НЕ уникально.

Мое требование таково, что «имя» должно быть уникальным для разных значений «id». Однако может существовать несколько документов с одним и тем же «идентификатором» и одним и тем же «именем». (В одном и том же «id» может быть несколько «имен»).

Например:
Разрешены следующие документы (один и тот же идентификатор, одинаковые/разные имена):

{ "id" : "1", "name": "Alice"}  
{ "id" : "1", "name": "Bob"}  
{ "id" : "1", "name": "Alice"}

Однако следующее не разрешено (то же имя, разные идентификаторы):

{ "id" : "1", "name": "Alice"}  
{ "id" : "2", "name": "Alice"}

Можно ли реализовать это в самой базе данных, а не в логике приложения?

Почему вы отметили тегами CosmosDB и MongoDB? Стоит ли отмечать azure-cosmosdb-mongoapi? Это то, что вы на самом деле используете?

Martin Smith 01.09.2024 14:32

Да, это то, что я использую. Спасибо за указание - я не видел этого тега в списке. Поскольку я могу использовать большую часть документации MongoDB как есть, я пометил ее тегом mongo-db.

ksceriath 02.09.2024 07:00
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
Как установить LAMP Stack 1/2 на Azure Linux VM
Как установить LAMP Stack 1/2 на Azure Linux VM
В дополнение к нашему предыдущему сообщению о намерении Azure прекратить поддержку Azure Database для MySQL в качестве единого сервера после 16...
0
2
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я думаю, что невозможно «обеспечить соблюдение» правила с существующими данными только с помощью базы данных. Возможно, вам придется выполнить единоразовую очистку, если у вас есть данные, которые нарушают правило. Однако для вновь вставленных документов вы можете выполнить следующие действия и объединить их в коллекцию.

  1. $unionWith новые документы, которые вы хотели вставить (вставив их $documents
  2. $setWindowFields для вычисления $denseRank внутри раздела name и в порядке id
    • В случае 1, если у них разные имена, они оба будут иметь ранг: 1.
    • В случае 2, если у них одинаковое имя и одинаковый идентификатор, они оба будут иметь ранг: 1.
    • В случае 3, если у них одинаковое имя, но разные идентификаторы, новый документ будет иметь рейтинг > 1.
  3. $match выбрать только документы с рангом: 1
  4. (косметика) $unset поле ранга
  5. $merge в коллекцию
db.collection.aggregate([
  {
    "$unionWith": {
      "coll": "collection",
      "pipeline": [
        {
          "$documents": [
            // documents to be inserted here
            {
              "id": "1",
              "name": "Alice"
            }
          ]
        }
      ]
    }
  },
  {
    "$setWindowFields": {
      "partitionBy": "$name",
      "sortBy": {
        "id": 1
      },
      "output": {
        "idRankInName": {
          "$denseRank": {}
        }
      }
    }
  },
  {
    "$match": {
      "idRankInName": 1
    }
  },
  {
    "$unset": "idRankInName"
  },
  {
    "$merge": {
      "into": "collection"
    }
  }
])

Mongo Playground для случаев 1 и 2
Игровая площадка Mongo для случая 3

Спасибо за ответ. Для меня это имеет смысл. Я верю в "coll": "collection", мы принимаем во внимание имеющиеся в коллекции документы? Кроме того, при этом кто-то все еще может писать код для вставки документов без этой логики. Можно ли каким-то образом запустить эту логику каждый раз, когда документы добавляются в эту коллекцию?

ksceriath 02.09.2024 09:23

@ksceriath Как я уже упоминал, я не думаю, что существует способ обеспечить соблюдение правила для каждой вставки только с помощью средств базы данных. На самом деле я рассмотрел триггеры и потоки изменений, но они включают в себя определенную часть кода приложения. Я предлагаю вам использовать приведенное выше решение как единственный способ вставки, если это возможно. Например, вы можете обернуть это как единый API вставки и представить его только как средство вставки данных в базу данных.

ray 02.09.2024 15:02

@ksceriath и насчет "coll": "collection", да, просто замените его на название вашей коллекции.

ray 02.09.2024 15:04

Другие вопросы по теме