programing

부울 필드를 "참이 아님"(예 : 거짓 또는 존재하지 않음)으로 쿼리

nasanasas 2020. 12. 3. 07:58
반응형

부울 필드를 "참이 아님"(예 : 거짓 또는 존재하지 않음)으로 쿼리


나는 MongoDB 쿼리에서 매우 기본적인 것을 놓치고 있다고 확신합니다.이 간단한 조건을 얻을 수 없습니다.

이 컬렉션 고려

> db.tests.find()
{ "_id" : ObjectId("..."), "name" : "Test1" , "deleted" : true}
{ "_id" : ObjectId("..."), "name" : "Test2" , "deleted" : false}
{ "_id" : ObjectId("..."), "name" : "Test3" }

"삭제되지 않은"모든 항목을 쿼리하고 싶습니다.

"삭제됨"플래그가 true로 설정된 항목을 찾는 방법을 알고 있습니다.

> db.tests.find({deleted:true})
{ "_id" : ObjectId("..."), "name" : "Test1" , "deleted" : true}

그러나 그렇지 않은 모든 항목을 어떻게 찾 "deleted"습니까 (예 : 위의 쿼리를 부정하거나 다른 말로 "deleted"필드가 없거나 값이있는 항목)false

추측 해 본 것 (웃지 말아주세요 ...)

> db.tests.find({$not : {deleted: true}})

(결과를 반환하지 않음)

> db.tests.find({$not : {$eq:{deleted:true}}})

오류 : { "$ err": "잘못된 연산자 : $ eq", "code": 10068}

> db.tests.find({deleted:{$not: true}})

오류 : { "$ err": "$ not의 잘못된 사용", "code": 13041}

> db.tests.find({deleted:{$not: {$eq:true}}})

오류 : { "$ err": "$ not의 잘못된 사용", "code": 13034}

내가 무엇을 놓치고 있습니까?


db.tests.find({deleted: {$ne: true}})

어디 $ne를 의미합니다 "동일하지". ( mongodb 연산자에 대한 문서 )


완전성을 위해이 작업을 수행하는 또 다른 방법은 다음과 $in같습니다.

db.test.find({deleted: {$in: [null, false]}})

null배열에 포함 하면 deleted필드가 누락 된 문서를 가져옵니다 . 이 쿼리는 {deleted: 1}현재 2.6.6 MongoDB 릴리스 의 인덱스를 사용할 수 있습니다 .


JohnnyHK가 최고의 답을 가지고 있습니다. $in선택기 IMO 짧고 깨끗하다.

이것은 정확히 "거짓"또는 "존재하지 않음"을 테스트합니다. 그리고 색인화 될 수 있습니다.

db.tests.find({$or:[{deleted:false},{deleted:{$exists:false}}]})

인덱스를 사용한 예.

((function(){
    print("creating collection 'testx' and inserting 50 trues, 50 falses, 50 non-existents");
    db.testx.drop();
    db.testx.ensureIndex({deleted:1});
    for (var i=0;i<50;i++){
        db.testx.insert({i:i,deleted:false});
    };
    for (var i=0;i<50;i++){
        db.testx.insert({i:i,deleted:true});
    };
    for (var i=0;i<50;i++){
        db.testx.insert({i:i});
    };
    var res0 = db.testx.find().explain();
    var res1 = db.testx.find({deleted:false}).explain();
    var res2 = db.testx.find({deleted:true}).explain();
    var res3 = db.testx.find({deleted:{$exists:false}}).explain();
    var res4 = db.testx.find({$or:[{deleted:false},{deleted:{$exists:false}}]}).explain();
    var res5 = db.testx.find({$or:[{deleted:true},{deleted:{$exists:false}}]}).explain();
    var res6 = db.testx.find({deleted:{$in:[false,null]}}).explain();
    print("res0: all objects                      ("+res0["n"]+" found, "+res0["nscannedObjects"]+" scanned)");
    print("res1: deleted is false                 ("+res1["n"]+" found, "+res1["nscannedObjects"]+" scanned)");
    print("res2: deleted is true                  ("+res2["n"]+" found, "+res2["nscannedObjects"]+" scanned)");
    print("res3: deleted is non-existent          ("+res3["n"]+" found, "+res3["nscannedObjects"]+" scanned)");
    print("res4: deleted is false or non-existent ("+res4["n"]+" found, "+res4["nscannedObjects"]+" scanned)");
    print("res5: deleted is true or non-existent  ("+res5["n"]+" found, "+res5["nscannedObjects"]+" scanned)");
    print("res6: deleted is in [false,null]       ("+res5["n"]+" found, "+res5["nscannedObjects"]+" scanned)");
})())

이것은 인쇄되어야합니다

creating collection 'testx' and inserting 50 trues, 50 falses, 50 non-existents
res0: all objects                      (150 found, 150 scanned)
res1: deleted is false                 (50 found, 50 scanned)
res2: deleted is true                  (50 found, 50 scanned)
res3: deleted is non-existent          (50 found, 50 scanned)
res4: deleted is false or non-existent (100 found, 100 scanned)
res5: deleted is true or non-existent  (100 found, 100 scanned)
res6: deleted is in [false,null]       (100 found, 100 scanned)

For the case that someone needs this in an aggregation pipeline instead of find, this is what worked for me

db.getCollection('tests').aggregate([ 
  // ...previous operations...
  { $addFields: { "deleted_conclusion": { $cond: {
        if:{ $ne: [ "$deleted", false ]}, then: { $cond: [ "$deleted", ":TRUE", ":FALSY"]}, else: ":FALSE"
  }}}}
])

After adding the extra field you can go on with pipeline stages and have the information you miss


In case you are looking for mongoid syntax (I am using this in a rails app), this is what I came up with for a company's users:

2.3.1 :042 > accepted_consent = org.users.active.where(:accepted_terms_and_conditions => true).count
 => 553 
2.3.1 :043 > not_accepted_yet = org.users.active.where(:accepted_terms_and_conditions.ne => true).count
 => 6331 
2.3.1 :044 > 6331+553
 => 6884 
2.3.1 :045 > org.users.active.count
 => 6884 

참고URL : https://stackoverflow.com/questions/18837486/query-for-boolean-field-as-not-true-e-g-either-false-or-non-existent

반응형