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


103

고유 컬렉션 항목을 강제하는 방법이 있지만 항목이 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 쿼리를 저장하고 싶습니다.

고마워

답변:


168

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/를


18
대박! 1.8 이후 저와 같은 newbs에 대한 최고의 답변입니다! 참고 : 스키마에 sparse : true를 추가하면 Mongoose는 고유 인덱스를 희소로 업데이트하지 않습니다. 인덱스를 삭제하고 다시 추가해야합니다. 그것이 예상되거나 버그라면 Dunno.
아담 A

8
"참고 : 색인이 이미 db에 존재하는 경우 대체되지 않습니다." - mongoosejs.com/docs/2.7.x/docs/schematypes.html
damphat

특정 필드가없는 몇 개의 문서는 해당 필드에 null 값이있는 몇 개의 문서 (고유하게 색인화 될 수 없음)와 동일하지 않기 때문에 이것이 질문에 올바르게 대답한다고 생각하지 않습니다.
kako-nawao

1
@ kako-nawao 사실, email필드가없는 문서에서만 작동하며 실제로 값이있는 곳이 아닙니다 null. 업데이트 된 답변을 참조하십시오.
JohnnyHK 2015-06-24

2
누락 된 필드에서는 작동하지 않습니다. mongodb의 이후 버전에서 동작이 변경되었을 수 있습니다. 답변을 업데이트해야합니다.
joniba

44

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이메일을 포함하거나 이메일 필드없이 여러 레코드를 삽입 할 수 있지만 동일한 이메일 문자열 은 삽입 할 수 없습니다.


멋진 대답입니다. 당신은 구세주입니다.
r3wt

이 대답은 나에게도 해주었습니다.
엠마뉴엘 NK

1
이 질문에 대해 허용되는 대부분의 답변은 인덱싱 된 키에 null 값을 명시 적으로 설정하지 않았는지 확인하는 것과 관련이 있습니다. 대신 정의되지 않은 상태로 전달됩니다. 나는 그것을하고 있었고 여전히 오류가 발생했습니다 ( unique및 사용하는 동안 sparse). 이 답변으로 스키마를 업데이트하고 기존 색인을 삭제했으며 매력처럼 작동했습니다.
Phil

가장 일반적인 시나리오를 기반으로 지식과 가능한 답변을 제공하기 때문에이 질문에 투표했습니다. 자세한 답변 주셔서 감사합니다! : +1 :
anothercoder

6

이 주제를 연구하는 사람들에게 간단한 업데이트입니다.

선택한 답변이 작동하지만 대신 부분 색인 사용을 고려할 수 있습니다.

버전 3.2에서 변경 : MongoDB 3.2부터 MongoDB는 부분 인덱스를 생성하는 옵션을 제공합니다. 부분 인덱스는 희소 인덱스 기능의 상위 집합을 제공합니다. MongoDB 3.2 이상을 사용하는 경우 부분 인덱스가 희소 인덱스보다 선호되어야합니다.

부분 색인에 대한 추가 문서 : https://docs.mongodb.com/manual/core/index-partial/


2

실제로 "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 도 읽어보십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.