2017-03-23 1 views
12

상황 : 동일한 컬렉션 (계정)의 문서가 여러 개 있는데 각각 uniquestrings이라는 array (문자열) 유형의 속성이 있습니다.하나의 컬렉션에있는 모든 문서에 대해 고유 한 값을 가진 배열

문제점 : uniquestrings의 각 항목은 mongodb의 모든 문서에서 고유해야합니다. MongoDB/Mongoose는 이러한 유효성 검사 (addToSet¹도 색인도 제공하지 않습니다 : {unique : true} ²가 문제를 해결하지 못함)를 제공하는 것 같습니다. mongodb 자체에서 유효성을 검사 할 수 있도록 내 문서 스키마를 재구성하는 패턴이 있습니까? 현재 문서를 업데이트하기 전에 소프트웨어 자체에서 확인합니다.

예.

account { 
    _id: 111, 
    uniquestrings: ["a", "b", "c"] 
} 

account { 
    _id: 222, 
    uniquestrings: ["d", "e", "f"] 
} 

예 : mongo에서 중복 오류가 발생하여 account(222).uniquestrings.push("a");을 방지하십시오.

추가 예 :

배열 고유성을 ¹하는 배열의 각 항목이 수집 걸쳐

갱신 1 고유해야
² 충분하지 않다. 영향을받는 스키마 항목은 다음과 같습니다.

var Account = new Schema({ 
    ... 
    uniquestrings: [{type: String, index: {unique: true}}] 
    ... 
}); 

이제 4 개의 계정 문서를 만들 때. 나는 단지 1과 2가 좋기를 바랄 뿐이다. 그리고 나머지는 실패해야한다.

var accountModel1 = new Account.Model({uniquestrings: ["a", "b"]}); 
accountModel1.save(); // OK 
var accountModel2 = new Account.Model({uniquestrings: ["c", "d"]}); 
accountModel2.save(); // OK 
var accountModel3 = new Account.Model({uniquestrings: ["c", "d"]}); 
accountModel3.save(); // FAIL => Not unique, so far so good 
var accountModel4 = new Account.Model({uniquestrings: ["X", "d"]}); 
accountModel4.save(); // OK => But i Want this to faile because "d" is alreay in use. 
+0

문제가 어디에서 발생하는지 이해할 수 없습니다 ... 방금 테스트를 수행했으며 고유 인덱스 (mongo 셸 사용)로 제대로 작동합니다. 문제가있는 js 코드를 게시 할 수 있습니까? – felix

+0

색인을 어떻게 만들었습니까? – styvane

답변

5

고유 한 값 을 다른 컬렉션에 저장하려는 경우 가능할 수 있습니다. 내가 몽구스와 전문가가 아니다

{ "uniquestring" : "a", "account" : 111 } 
{ "uniquestring" : "b", "account" : 111 } 
{ "uniquestring" : "c", "account" : 111 } 
{ "uniquestring" : "d", "account" : 222 } 
{ "uniquestring" : "e", "account" : 222 } 
{ "uniquestring" : "f", "account" : 222 } 

,하지만 난 당신이 계정 필드가 여기에 계정 수집의 _id 필드를 참조와 함께 컬렉션을 연결하는 모델을 정의 할 수 있다고 생각합니다 : 다음과 같이 구성된다.

지금, 당신은 간단한 인덱스 고유성을 적용 할 수 있습니다 :

db.uniquestrings.createIndex({ "uniquestring" : 1 } , { unique : true }) 

지금, 당신의 앱이 데이터를 저장할 때 약간의 추가 작업이 필요합니다 (그것은뿐만 아니라 uniquestrings 컬렉션에 저장해야합니다 계정 콜렉션으로 사용), 이제는 데이터베이스에서 이러한 문자열의 고유성에 대한 데이터베이스 수준의 적용을가집니다.

PS 편집은 몽구스에서 그러한 모델을 구현하고 사용하는 방법에 대한보다 자세한 지식을 가진 누구나 환영합니다.

+0

흥미로운 패턴. 아프다. – MortalFool

4

this MongoDB Doc에 따르면, 내에서 하나의 문서를 고유 인덱스 정책 을 적용하여 MongoDB를 강제 할 방법은 없습니다 만, 별도의 문서 내에서 시행 할 수있는 방법이있다.

db.collection.createIndex("a.b"); 

은 ... a.b에 이들에 대한 고유성을 것입니다 ...

db.collection.insert({ a: [{b: 1}] }); 
db.collection.insert({ a: [{b: 1}] }); 

...하지만 ... 이것에 대한

db.collection.insert({ a: [{b: 1},{b: 1}] ]); 

을 고유성을 적용하지 않습니다 ... BUT$addToSet의 색인을 사용하는 경우 ...

... 예외가 발생하지 않아 타협하지만, 업서트는 복제물을 조용히 무시합니다. 이는 원하는 것이 아니라 더 가까운 것으로 간주합니다.

지금까지 Google에서 답변 한 내용을 another SO question에 대해 다뤘지만 계속해서 읽으면 어떨까요? 위의 지시에 따라 달리 upsert 지금

, 당신은 기본 MongoDB의 요청으로 요청하는 것을 달성하기는 상자 밖으로 수 없습니다,하지만 당신은 ensureIndex을 할 수 있었던 인덱스 배열을 조회하고 당신이 그것을 발견하면 오류가 발생하는 covered query를 사용 .

그래서 ...

// Ensure index 
db.collection.createIndex({ 'a.b': 1 }); 

// Test for existence and throws up if not unique 
function insertUnique(newVal) { 
    var exists = db.collection.find({'a.b': newVal}); 
    if (exists) { 
    throw "Element is not unique in the collection: " + newVal; 
    } else { 
    db.collection.upsert({ $addToSet: { a: { b: 1 } } }); 
    } 
} 

// Use it later... 
try { 
    insertUnique(1); 
    insertUnique(1); // it should barf 
} catch (e) { 
    console.warn(e); 
} 

마지막으로, 당신이 사용하는 클라이언트에 따라, 당신은 insertUnique 방법 (JS)에 프로토 타입을 확장 할 수 있으며, 곧 당신은 당신이 처음부터이 작업을 수행 할 수 잊지 있습니다.

+0

좋은 설명. 그러나 내가 바라는 해결책은 "isunique"수표에 의존해서는 안됩니다. – MortalFool

+1

물론 ... 유니크 스트링의 배열에 대한 요구 사항을 기꺼이 따르려한다면 @Vince Bowdren이 제안한 인덱스 제한 관계형 해시 맵을 만들어야합니다. :) – toszter

관련 문제