mongoDB/Мангуст: уникальный, если не null


мне было интересно, есть ли способ заставить уникальную запись коллекции но только если запись не null. е Пример схемы:

var UsersSchema = new Schema({
    name  : {type: String, trim: true, index: true, required: true},
    email : {type: String, trim: true, index: true, unique: true}
});

' email 'в этом случае не требуется, но если' email ' сохранен, я хочу убедиться, что эта запись уникальна (на уровне базы данных).

пустые записи, похоже, получают значение "null", поэтому каждая запись без сбоев электронной почты с опцией "уникальный" (если есть другой пользователь без электронной почты).

сейчас я решение его на уровне приложения, но хотелось бы сохранить этот запрос БД.

thx

4 70

4 ответа:

С MongoDB v1. 8+ вы можете получить желаемое поведение обеспечения уникальных значений, но позволяя несколько документов без поля, установив true при определении индекса. Как в:

email : {type: String, trim: true, index: true, unique: true, sparse: true}

или в оболочке:

db.users.ensureIndex({email: 1}, {unique: true, sparse: true});

обратите внимание, что уникальный разреженный индекс по-прежнему не позволяет использовать несколько документов с

tl; dr

Да, это можно сделать.
Несколько документов с полем, установленным в null или не определено, при этом применяются уникальные "фактические" значения.

требования:

  • MongoDB v3.2+.
  • если у вас полеר имеет фактическое значение, оно должно быть определенного типа (например, всегда строка).

как? Перейдите к деталям реализации ниже.

больше версия

чтобы дополнить ответ @Nolan, начиная с MongoDB v3.2, Вы можете использовать частичный уникальный индекс с выражением фильтра.

выражение частичного фильтра имеет ограничения. Он может включать только следующее:

  • выражения равенства (т. е. поле: Значение или с помощью $eq оператор),
  • $exists: true выражение
  • $gt,$gte,$lt,$lte выражения
  • $type выражения
  • $and оператор только на верхнем уровне

это означает, что тривиальное выражение {"yourField"{$ne: null}} не может быть использован.

однако, предполагая, что ваше поле всегда использует один и тот же тип, вы можете использовать $type выражение.

{ field: { $type: <BSON type number> | <String alias> } }

реализация

мангуста

вы можете указать его в мангуста схема:

const UsersSchema = new Schema({
  name: {type: String, trim: true, index: true, required: true},
  email: {
    type: String, trim: true, index: {
      unique: true,
      partialFilterExpression: {email: {$type: 'string'}}
    }
  }
});

или непосредственно добавить его в коллекцию (которая использует собственный узел.водитель с JS):

User.collection.createIndex("email", {
  unique: true,
  partialFilterExpression: {
    "email": {
      $type: "string"
    }
  }
});

родной драйвер mongodb

используя collection.createIndex

db.collection('users').createIndex({
    "email": 1
  }, {
    unique: true,
    partialFilterExpression: {
      "email": {
        $type: "string"
      }
    }
  },
  function (err, results) {
    // ...
  }
);

командной оболочки MongoDB

используя db.collection.createIndex:

db.users.createIndex({
  "email": 1
}, {
  unique: true, 
  partialFilterExpression: {
    "email": {$type: "string"}
  }
})

это позволит вставить несколько записей с null электронная почта, или без поля электронной почты вообще, но не с той же строкой электронной почты.

просто быстрое обновление для тех, кто исследует эту тему.

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

изменено в версии 3.2: начиная с MongoDB 3.2, MongoDB предоставляет возможность создания частичных индексов. Частичные индексы предлагают надмножество функциональность разреженных индексов. Если вы используете MongoDB 3.2 или позже, частичные индексы должны быть предпочтительнее, чем редкие индексы.

дополнительные документы по частичным индексам:https://docs.mongodb.com/manual/core/index-partial/

на самом деле, только первый документ, где "электронная почта" как поле не существует будет получить сохранить успешно. Последующие сохранения, где "электронная почта" отсутствует, завершатся ошибкой ( см. фрагмент кода ниже). По этой причине посмотрите на официальную документацию MongoDB в отношении уникальных индексов и отсутствующих ключей здесь http://www.mongodb.org/display/DOCS/Indexes#Indexes-UniqueIndexes.

  // NOTE: Code to executed in mongo console.

  db.things.ensureIndex({firstname: 1}, {unique: true});
  db.things.save({lastname: "Smith"});

  // Next operation will fail because of the unique index on firstname.
  db.things.save({lastname: "Jones"});

С помощью уникального индекса определение может разрешить только одно значение, которое будет сохранено только однажды. Если вы считаете null одним из таких значений, его можно вставить только один раз! Вы правы в своем подходе, обеспечивая и проверяя его на уровне приложения. Вот как это можно сделать.

вы также можете прочитать это http://www.mongodb.org/display/DOCS/Querying+и+нули