2017-12-17 43 views
0

개인 정보 설정이 제공된 것과 일치하는 문서와 개인 정보 설정 (예 : 공용)이없는 문서를 선택하려고합니다.

현재 동작은 그 나는 다른 컬렉션에 참조 된 개체 ID의 배열과 스키마가있는 경우 :

privacy: [{ 
    type: mongoose.Schema.Types.ObjectId, 
    ref: 'Category', 
    index: true, 
    required: true, 
    default: [] 
}], 

을 그리고 우리의 경우 함량, 내 범주와 대중들에 대한 모든 콘텐츠를 필터링 할 개인 정보 보호 설정이 없습니다. 즉 하늘의 배열은 []

우리는 현재 또는 쿼리

{"$or":[ 
    {"privacy": {"$size": 0}}, 
    {"privacy": {"$in": 
     ["5745bdd4b896d4f4367558b4","5745bd9bb896d4f4367558b2"]} 
    } 
]} 

와 나는 단지 [] 하나 문에서 $의 비교 옵션을 하늘의 배열을 제공하여 쿼리 사랑한다고 쿼리합니다.

db.emptyarray.insert({a:1}) 
db.emptyarray.insert({a:2, b:null}) 
db.emptyarray.insert({a:2, b:[]}) 
db.emptyarray.insert({a:3, b:["perm1"]}) 
db.emptyarray.insert({a:3, b:["perm1", "perm2"]}) 
db.emptyarray.insert({a:3, b:["perm1", "perm2", []]}) 
> db.emptyarray.find({b:[]}) 
{ "_id" : ObjectId("5a305f3dd89e8a887e629ce0"), "a" : 2, "b" : [ ] } 
{ "_id" : ObjectId("5a305f3dd89e8a887e629ce3"), "a" : 3, "b" : [ "perm1", "perm2", [ ] ] } 
> db.emptyarray.find({b:{$in:[]}}) 
> db.emptyarray.find({b:{$in:[[], "perm1"]}}) 
{ "_id" : ObjectId("5a305f3dd89e8a887e629ce0"), "a" : 2, "b" : [ ] } 
{ "_id" : ObjectId("5a305f3dd89e8a887e629ce1"), "a" : 3, "b" : [ "perm1" ] } 
{ "_id" : ObjectId("5a305f3dd89e8a887e629ce2"), "a" : 3, "b" : [ "perm1", "perm2" ] } 
{ "_id" : ObjectId("5a305f3dd89e8a887e629ce3"), "a" : 3, "b" : [ "perm1", "perm2", [ ] ] } 
> db.emptyarray.find({b:{$in:[[], "perm1", null]}}) 
{ "_id" : ObjectId("5a305f3dd89e8a887e629cde"), "a" : 1 } 
{ "_id" : ObjectId("5a305f3dd89e8a887e629cdf"), "a" : 2, "b" : null } 
{ "_id" : ObjectId("5a305f3dd89e8a887e629ce0"), "a" : 2, "b" : [ ] } 
{ "_id" : ObjectId("5a305f3dd89e8a887e629ce1"), "a" : 3, "b" : [ "perm1" ] } 
{ "_id" : ObjectId("5a305f3dd89e8a887e629ce2"), "a" : 3, "b" : [ "perm1", "perm2" ] } 
{ "_id" : ObjectId("5a305f3dd89e8a887e629ce3"), "a" : 3, "b" : [ "perm1", "perm2", [ ] ] } 
> db.emptyarray.find({b:{$in:[[]]}}) 
{ "_id" : ObjectId("5a305f3dd89e8a887e629ce0"), "a" : 2, "b" : [ ] } 
{ "_id" : ObjectId("5a305f3dd89e8a887e629ce3"), "a" : 3, "b" : [ "perm1", "perm2", [ ] ] } 

어쩌면이 같은 : MongoDB를 가능한 어느

"privacy_locations":{ 
    "$in": ["5745bdd4b896d4f4367558b4","5745bd9bb896d4f4367558b2",[]] 
} 

그러나이 쿼리, 그것은 주조 오류가 발생합니다 코드에서 콘솔 (CLI)에서 작동하지만,하지 :

{ 
    "message":"Error in retrieving records from db.", 
    "error": 
     { 
     "message":"Cast to ObjectId failed for value \"[]\" at ... 
     } 
} 

이제 스키마가 ObjectId로 정의 되었기 때문에 캐스트가 발생하는 것을 완벽하게 이해합니다.

하지만이 방법에는 가능한 두 가지 시나리오가 없습니다.

$ in 문 내에서 null 옵션이나 빈 배열을 (MongoDB에서) 쿼리 할 수 ​​있다고 생각합니다.

array: {$in:[null, [], [option-1, option-2]}

이 맞습니까?

내 문제 (옵션 또는 빈에서는 선택할 수 없음)에 대한 최선의 해결책은 빈 배열이 예를 들어 ALL의 수정 옵션을 가진 배열이 될 수 있다고 생각 해왔다. 프라이버시를위한 설정은 그것이 현재 설정되지 않은 경우 ALL이 아니라 설정 된 경우 모든 것을 의미하는 ALL을 의미합니다.

기존 코드의 주요 리팩터를 원하지는 않지만 더 나은 쿼리를 만들 수 있는지 또는 성능이 좋은 쿼리를 만들 수 있는지 확인해야합니다.

오늘 우리는 인덱스에 문제가있는 $ OR 문으로 작업하는 쿼리가 있습니다. 그리고 비록 그것이 빠르더라도, 나는 버그로 간주되지 않더라도이 문제에주의를 기울이고 싶었습니다.

모든 의견이나 안내를 부탁드립니다.

답변

0

반 단답형은 엄격 스키마 타입의 ObjectId임을 선언하면서 privacy 스키마가 속성 (및 ObjectIdArray)에 대한 종류를 혼합된다는 것이다.

MongoDB는 스키마가 없으므로 문서마다 모든 문서 모양을 허용하며 스키마와 일치하도록 쿼리 문서를 확인할 필요가 없습니다. Mongoose는 스키마 적용을 적용하기위한 것이므로 DB 쿼리를 시도하기 전에 스키마에 대해 쿼리 문서를 확인합니다.빈 배열이 오류로 표시되는 유효한 ObjectId이 아니므로 { privacy: { $in: [[]] } }에 대한 쿼리 문서는 유효성 검사에 실패합니다.

ObjectId뿐만 아니라 허용되는 유형으로 빈 배열을 계속 사용하려면 스키마에서 Mixed (ref을 지원하지 않음)을 선언해야합니다.

// Current 
const FooSchema = new mongoose.Schema({ 
    privacy: [{ 
    type: mongoose.Schema.Types.ObjectId, 
    ref: 'Category', 
    index: true, 
    required: true, 
    default: [] 
    }] 
}); 

const Foo = connection.model('Foo', FooSchema); 

const foo1 = new Foo(); 
const foo2 = new Foo({privacy: [mongoose.Types.ObjectId()]}); 

Promise.all([ 
    foo1.save(), 
    foo2.save() 
]).then((results) => { 
    console.log('Saved', results); 
    /* 
    [ 
    { __v: 0, _id: 5a36e36a01e1b77cba8bd12f, privacy: [] }, 
    { __v: 0, _id: 5a36e36a01e1b77cba8bd131, privacy: [ 5a36e36a01e1b77cba8bd130 ] } 
    ] 
    */ 

    return Foo.find({privacy: { $in: [[]] }}).exec(); 
}).then((results) => { 
    // Never gets here 
    console.log('Found', results); 
}).catch((err) => { 
    console.log(err); 
    // { [CastError: Cast to ObjectId failed for value "[]" at path "privacy" for model "Foo"] } 
}); 

및 작동 버전. 필수 플래그, 인덱스 플래그 및 기본값을 올바르게 적용하기위한 조정에 유의하십시오.

// Updated 
const FooSchema = new mongoose.Schema({ 
    privacy: { 
    type: [{ 
     type: mongoose.Schema.Types.Mixed 
    }], 
    index: true, 
    required: true, 
    default: [[]] 
    } 
}); 

const Foo = connection.model('Foo', FooSchema); 

const foo1 = new Foo(); 
const foo2 = new Foo({ 
    privacy: [mongoose.Types.ObjectId()] 
}); 

Promise.all([ 
    foo1.save(), 
    foo2.save() 
]).then((results) => { 
    console.log(results); 
    /* 
    [ 
     { __v: 0, _id: 5a36f01733704f7e58c0bf9a, privacy: [ [] ] }, 
     { __v: 0, _id: 5a36f01733704f7e58c0bf9c, privacy: [ 5a36f01733704f7e58c0bf9b ] } 
    ] 
    */ 

    return Foo.find().where({ 
    privacy: { $in: [[]] } 
    }).exec(); 
}).then((results) => { 
    console.log(results); 
    // [ { _id: 5a36f01733704f7e58c0bf9a, __v: 0, privacy: [ [] ] } ] 
}); 
+0

"에 대한 쿼리 문서 {개인 정보 보호 : {$에서 [[]]가}}. 오류로 표시된 바와 같이, 하늘의 배열이 유효한 ObjectId가 아니기 때문에 검증을 실패합니다" []가 ObjectID를 나타내는 것으로 생각하지 않습니다. 어떤 배열의 내용입니다. 0 개의 ObjectId의 배열은 비어있는 ARRAY []입니다. 그리고 나는 objectInd 중 하나가 맞지 않기 때문에 objectid 또는이 경우에는 문자열을 포함한다면 주어진 $ 옵션이 주어진 옵션을 통과한다고 생각합니까? 옵션을 통해 ObjectId로 캐스팅되고 NULL 또는 빈 배열 옵션을 평가할 수 있어야합니다. 프라이버시가 null이면 OID가 –

+0

mongo의 문서에서'$ in' : "_ 필드에 배열이 있으면'$ in' 연산자는 필드에 값과 일치하는 적어도 하나의 요소가 들어있는 배열을 가진 문서를 선택합니다 지정된 배열에 있습니다 (예 : , 등). " 즉, mongo는 배열의 요소를 쿼리 된 문서 속성의 배열 값과 일치하는지 확인하려고 배열을 반복합니다. 스키마는 ObjectIds의 배열임을 스키마가 선언 했으므로 Mongoose는 쿼리 문서의 모든 값을 ObjectId로 캐스팅하려고 시도합니다. 따라서이 개체는 오류를 발생시킵니다. –

+0

privacy가 emtpy [] like {privacy : []} 인 경우, [[], ObjectId ('xxxx')의 $는 개인 정보 보호의 가치이기 때문에 []와 일치합니다. where 절과 결과가 내가 필요한 것이 아닙니다. CLI 예제를 추가했습니다. Foo.find(). where ({privacy : {$ in : [[]]}})는 하나의 문서가 빈 배열을 가지므로 하나의 문서 만 반환해야하고, 다른 하나는 인스턴스가있는 배열을가집니다. ObjectId. 다르게 써주세요. 프라이버시 유형이 ObjectId 인 경우 objectid 또는 null 일 수 있습니다. OID 배열 인 경우 Null, [] 또는 값을 유지할 수 있습니다. 이 3 가지 값을 보유하기 위해 혼합 유형이 필요하지 않습니다. –