두 필드 비교시 MongoDb 쿼리 조건


108

나는 모음이 T두 필드를 : Grade1그리고 Grade2, 나는 조건을 가진 사람을 선택합니다 Grade1 > Grade2내가 MySQL은 같은 쿼리를 얻을 수있는 방법?

Select * from T Where Grade1 > Grade2

답변:


120

$ where를 사용할 수 있습니다. 속도가 상당히 느리므로 (모든 레코드에서 Javascript 코드를 실행해야 함) 가능하면 색인화 된 쿼리와 결합하십시오.

db.T.find( { $where: function() { return this.Grade1 > this.Grade2 } } );

또는 더 콤팩트 :

db.T.find( { $where : "this.Grade1 > this.Grade2" } );

mongodb v.3.6 + 용 UPD

최근 답변에$expr 설명 된대로 사용할 수 있습니다.


아, 알겠습니다. 자바 스크립트 나 다른 쉘 스크립트를 공동으로 사용하세요. 두 분 모두 감사합니다!
Diego Cheng

16
당신은 이것을 좀 더 간결하게 할 수도 있습니다 ...> db.T.find ({$ where : "this.Grade1> this.Grade2"});
Justin Jenkins

내가 $where: function() { return this.Grade1 - this.Grade2 > variable }어떻게?
Luis González

내가 시도했을 때 db.T.find({$where: function() {return this.startDate == ISODate("2017-01-20T10:55:08.000Z");}});아무것도 반환하지 않으며 컬렉션의 문서 중 하나조차도 ISODate("2017-01-20T10:55:08.000Z"). 그러나 <=>=작업을 보인다. 어떤 생각?
cateyes

@cateyes 아마도 조금 늦었을 것입니다 ...하지만 순수한 자바 스크립트는 == 두 날짜 사이를 비교할 때 항상 false를 반환합니다. 그러나 Mongo를 사용하면 쿼리의 날짜간에 정확히 일치하는 항목을 검색 할 수 있습니다. 한 가지 해결 방법은 .getTime ()을 사용하여 밀리 초 등으로 변환하는 것입니다.this.startDate.getTime() == ISODate("2017-01-20T10:55:08.000Z").getTime()
leinaD_natipaC

53

당신이 사용할 수있는 $ expr에 일반 쿼리에서 집계 함수를 사용하는 (3.6 몽고 버전 연산자).

비교 query operatorsaggregation comparison operators.

일반 쿼리 :

db.T.find({$expr:{$gt:["$Grade1", "$Grade2"]}})

집계 쿼리 :

db.T.aggregate({$match:{$expr:{$gt:["$Grade1", "$Grade2"]}}})

39

쿼리가 $where연산자 로만 구성된 경우 JavaScript 표현식 만 전달할 수 있습니다.

db.T.find("this.Grade1 > this.Grade2");

성능을 $redact높이려면 파이프 라인 이있는 집계 작업을 실행 하여 주어진 조건을 충족하는 문서를 필터링하십시오.

$redact파이프 라인의 기능을 통합 $project하고 $match그것을 사용 조건과 일치하는 모든 문서를 반환 필드 레벨 편집 구현하는 $$KEEP파이프 라인 결과에서 사용하여 일치하지 않는 것들과 제거합니다 $$PRUNE변수.


다음 집계 작업을 실행하면 $where대규모 컬렉션에 사용하는 것보다 문서를 더 효율적으로 필터링 할 수 있습니다.을 사용하는 자바 스크립트 평가 대신 단일 파이프 라인과 네이티브 MongoDB 연산자 $where를 사용하므로 쿼리 속도가 느려질 수 있습니다.

db.T.aggregate([
    {
        "$redact": {
            "$cond": [
                { "$gt": [ "$Grade1", "$Grade2" ] },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])

이는 두 개의 파이프 라인 통합을보다 간략화 버전 $project$match:

db.T.aggregate([
    {
        "$project": {
            "isGrade1Greater": { "$cmp": [ "$Grade1", "$Grade2" ] },
            "Grade1": 1,
            "Grade2": 1,
            "OtherFields": 1,
            ...
        }
    },
    { "$match": { "isGrade1Greater": 1 } }
])

MongoDB를 3.4 및 최신 :

db.T.aggregate([
    {
        "$addFields": {
            "isGrade1Greater": { "$cmp": [ "$Grade1", "$Grade2" ] }
        }
    },
    { "$match": { "isGrade1Greater": 1 } }
])

마지막 것은 나와 함께 작동하지 않는 것 같습니다. isGrade1Greater 필드가 제대로 추가되고 평가되지만 어떤 이유로 쿼리는 isGrade1Greater의 값에 관계없이 모든 행과 일치합니다. 이 행동의 원인은 무엇일까요? 편집 : 신경 쓰지 마십시오 .aggregate ()에 배열을 전달하지 않고 각 집계를 매개 변수 자체로 전달하지 못했습니다.
ThatBrianDude 2017-08-24

13

가독성보다 성능이 더 중요하고 조건이 간단한 산술 연산으로 구성된 경우 집계 파이프 라인을 사용할 수 있습니다. 먼저 $ project를 사용하여 조건의 왼쪽을 계산합니다 (모든 필드를 왼쪽으로 가져옴). 그런 다음 $ match를 사용하여 상수 및 필터와 비교합니다. 이렇게하면 자바 스크립트 실행을 피할 수 있습니다. 아래는 파이썬에서 내 테스트입니다.

import pymongo
from random import randrange

docs = [{'Grade1': randrange(10), 'Grade2': randrange(10)} for __ in range(100000)]

coll = pymongo.MongoClient().test_db.grades
coll.insert_many(docs)

집계 사용 :

%timeit -n1 -r1 list(coll.aggregate([
    {
        '$project': {
            'diff': {'$subtract': ['$Grade1', '$Grade2']},
            'Grade1': 1,
            'Grade2': 1
        }
    },
    {
        '$match': {'diff': {'$gt': 0}}
    }
]))

루프 1 개, 최고 1 : 루프 당 192ms

찾기 및 $ where 사용 :

%timeit -n1 -r1 list(coll.find({'$where': 'this.Grade1 > this.Grade2'}))

루프 1 개, 최고 1 : 루프 당 4.54 초

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