[mongodb] mongoDB / mongoose : null이 아닌 경우 고유

고유 컬렉션 항목을 강제하는 방법이 있지만 항목이 null이 아닌 경우에만 궁금합니다 . e 샘플 스키마 :

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’값을 가져 오는 것처럼 보이므로 이메일이없는 모든 항목은 ‘고유’옵션과 충돌합니다 (이메일이없는 다른 사용자가있는 경우).

지금은 응용 프로그램 수준에서 해결 중이지만 해당 db 쿼리를 저장하고 싶습니다.

고마워



답변

MongoDB v1.8 +부터는 sparse인덱스를 정의 할 때 옵션을 true 로 설정하여 고유 한 값을 보장하지만 필드없이 여러 문서를 허용하는 원하는 동작을 얻을 수 있습니다 . 에서와 같이 :

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

또는 셸에서 :

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

독특한 스파 스 인덱스는 여전히 여러 문서를 허용하지 않습니다 emailA의 필드 null경우에만 여러 문서, 없는email 필드.

참조 http://docs.mongodb.org/manual/core/index-sparse/를


답변

tl; dr

예, null고유 한 “실제”값을 적용하면서 필드가로 설정 되거나 정의되지 않은 여러 문서를 가질 수 있습니다.

요구 사항 :

  • MongoDB v3.2 이상.
  • 구체적인 값 유형을 미리 알고 있어야합니다 (예 : 항상 a string또는 object그렇지 않은 경우 null).

세부 사항에 관심이 없으면 implementation섹션 으로 건너 뛰어도됩니다 .

더 긴 버전

@Nolan의 답변을 보완하기 위해 MongoDB v3.2부터 필터 표현식과 함께 부분 고유 인덱스를 사용할 수 있습니다.

부분 필터 표현식에는 제한이 있습니다. 다음 만 포함 할 수 있습니다.

  • 등식 (예 : 필드 : 값 또는 $eq연산자 사용)
  • $exists: true 표현,
  • $gt, $gte, $lt, $lte표현,
  • $type 표현,
  • $and 최상위 수준에서만 연산자

이것은 사소한 표현이 {"yourField"{$ne: null}} 사용할 수 없음을 .

그러나 필드가 항상 동일한 유형을 사용 한다고 가정하면 $type표현식을 사용할 수 있습니다 .

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

MongoDB v3.6은 배열로 전달할 수있는 여러 유형을 지정하기위한 지원을 추가했습니다.

{ field: { $type: [ <BSON type1> , <BSON type2>, ... ] } }

이는 값이 아닌 경우 여러 유형 중 하나가 될 수 있음을 의미합니다 null.

따라서 email아래 예제 의 필드가 값 중 하나 string또는 binary data값 을 허용하도록 허용하려면 적절한 $type표현식은 다음과 같습니다.

{email: {$type: ["string", "binData"]}}

이행

몽구스

몽구스 스키마에서 지정할 수 있습니다.

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"}}
    }
  }
});

또는 컬렉션에 직접 추가합니다 (기본 node.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/


답변

실제로 “email”필드가 존재하지 않는 첫 번째 문서 만 성공적으로 저장됩니다. “email”이없는 후속 저장은 오류가 발생하는 동안 실패합니다 (아래 코드 스 니펫 참조). 그 이유는 http://www.mongodb.org/display/DOCS/Indexes#Indexes-UniqueIndexes 에서 고유 인덱스 및 누락 키에 관한 MongoDB 공식 문서를 참조하십시오 .

  // 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+and+nulls 도 읽어보십시오 .


답변