16. MongoDB Query Part 6. - $where

이번 포스팅에서는 $where key를 이용한 검색에 대해 알아보도록 하겠습니다.

$where는 JavaScript의 표현식 또는 JavaScript 함수 전체를 query에 전달할 수 있는 오퍼레이터입니다.

설명을 위해 우선 다음 데이터를 준비하도록 하겠습니다:

db.grade.insert({student_id : "01", korean : "A", english: "B", maths : "A+", science : "A" })
db.grade.insert({student_id : "02", korean : "B", english: "B", maths : "A+", science : "B" })
db.grade.insert({student_id : "03", korean : "C", english: "A+", maths : "A+", science : "A" })

위에 입력된 데이터를 살펴보면 다음과 같습니다:

> db.grade.find().pretty()
{
    "_id" : ObjectId("52efaab7614cff87320cc801"),
    "student_id" : "01",
    "korean" : "A",
    "english" : "B",
    "maths" : "A+",
    "science" : "A"
}
{
    "_id" : ObjectId("52efaab7614cff87320cc802"),
    "student_id" : "02",
    "korean" : "B",
    "english" : "B",
    "maths" : "A+",
    "science" : "B"
}
{
    "_id" : ObjectId("52efaab8614cff87320cc803"),
    "student_id" : "03",
    "korean" : "C",
    "english" : "A+",
    "maths" : "A+",
    "science" : "A"
}

참고로, find() 명령에 뒤에 있는 pretty()는 검색된 도큐먼트 내용을 잘 정리해서 보여주는 메써드입니다.

$where key를 이용하여 국어(korean)와 과학(science) 등급이 같은 학생을 추출해 보겠습니다:

> db.grade.find({ $where: function() { return (this.korean == this.science) }}).pretty();
{
    "_id" : ObjectId("52efaab7614cff87320cc801"),
    "student_id" : "01",
    "korean" : "A",
    "english" : "B",
    "maths" : "A+",
    "science" : "A"
}
{
    "_id" : ObjectId("52efaab7614cff87320cc802"),
    "student_id" : "02",
    "korean" : "B",
    "english" : "B",
    "maths" : "A+",
    "science" : "B"
}

국어와 과학 등급이 같은 학생의 ID는 "01"과 "02"입니다.

이와 같이 $where는 JavaScript 함수를 사용하여 query의 확장이 가능하게 합니다.

this 키워드가 사용되었음에 유의하시기 바랍니다.

유사하게, 이번에는 영어(english)와 수학(maths) 등급이 같은 학생을 추출하려면 다음과 같이 입력합니다:

> db.grade.find({ $where: function() { return (this.english == this.maths) }}).pretty();
{
    "_id" : ObjectId("52efaab8614cff87320cc803"),
    "student_id" : "03",
    "korean" : "C",
    "english" : "A+",
    "maths" : "A+",
    "science" : "A"
}

영어와 수학 등급이 같은 ID "03"의 학생이 검색되었음을 확인할 수 있습니다.

this 대신 obj를 사용해도 동일한 결과를 얻을 수 있습니다:

> db.grade.find({ $where: function() { return (obj.english == obj.maths) }}).pretty();
{
    "_id" : ObjectId("52efaab8614cff87320cc803"),
    "student_id" : "03",
    "korean" : "C",
    "english" : "A+",
    "maths" : "A+",
    "science" : "A"
}

함수 형태로 표현된 위의 표현은 보다 간단하게 다음과 같이 표현할 수 있으며, 결과는 동일합다.

> db.grade.find( { $where: "obj.english == obj.maths" } ).pretty();
{
    "_id" : ObjectId("52efaab8614cff87320cc803"),
    "student_id" : "03",
    "korean" : "C",
    "english" : "A+",
    "maths" : "A+",
    "science" : "A"
}

MongoDB의 정규 오퍼레이터로는 처리할 수 없는 것도 이를 사용해 처리가 가능하므로 확장 측면에서는 매우 유용하나, 동일한 데이터 처리를 하는 정규 오퍼레이터가 존재한다면 가급적 쓰지 않도록 합니다.

즉, 정말로 꼭 필요한 상황이 아니면 절대 써서는 안 됩니다.

왜냐하면, 정규 오퍼레이터보다 처리속도가 현저히 떨어지기 때문입니다.