04-29 02:46
Notice
Recent Posts
Recent Comments
관리 메뉴

Scientific Computing & Data Science

[MongoDB] Query / Querying Embedded Documents 본문

Data Science/MongoDB

[MongoDB] Query / Querying Embedded Documents

cinema4dr12 2014. 2. 2. 14:30

Written by cinema4d

임베드 된 도큐먼트에 대한 쿼리 방법은 크게 두 가지로 요약할 수 있다:

(1) 전체 도큐먼트에 대한 쿼리

(2) 개별 키(key)/값(value) 쌍을 이용한 쿼리


상기 두 가지 방법에 대해 각각 알아보도록 하겠다.


1. 전체 도큐먼트에 대한 쿼리

우선, 다음 명령을 통해 임베드 된 도큐먼트를 준비한다.

> db.users.drop() true > db.users.insert({name: {first: "john", last: "kennedy"}}) > db.users.findOne() { "_id" : ObjectId("52edaa32f97299c19188c2dc"), "name" : { "first" : "john", "last" : "kennedy" } }

"name" 안에 "first"(first name: 이름)과 "last"(last name: 성)이 임베드 되었다.

만약 이를 name: {first: "john", last: "kennedy"}로 검색한다면:

> db.users.findOne({name: {first: "john", last: "kennedy"}}) { "_id" : ObjectId("52edaa32f97299c19188c2dc"), "name" : { "first" : "john", "last" : "kennedy" } }

제대로 된 검색 결과를 얻을 수 있다. 이번에는 first와 last 순서를 바꿔 검색해 보면:

> db.users.findOne({name: {last: "kennedy", first:"john"}}) null

검색 결과가 없는 것으로(null) 결과를 반환한다. 즉, 임베드 된 도큐먼트 검색은 순서에 의존적(order-sensitive)인 것을 알 수 있다.

이번에는 name: {first: "john"}만으로 검색해 보자.

> db.users.findOne({name: {first: "john"}}) null

검색 결과가 없다. 마찬가지로 name: {last: "kennedy"}로 검색하더라도 검색 결과는 "null"로 반환될 것이다. 결론적으로, "전체 도큐먼트에 대한 쿼리"는 말 그대로 임베드 된 도큐먼트에 대한 내용 전체를 그대로 검색해야만 올바른 검색 결과를 얻을 수 있다.

만약 "name"에 middlename "fitzgerald"를 추가했다고 하면, 이제 앞의 검색방법으로는 원하는 검색결과를 얻을 수 없을 것이다.

이러한 단점을 극복하기 위해 MongoDB는 개별 키/값 쌍을 이용한 쿼리인 "$elemMatch"를 제공한다.


2. 개별 키/값 쌍을 이용한 쿼리

이제 쿼리를 엘리먼트 단위로 검색할 수 있는 "$elemMatch"를 살펴보자. 앞서 임베드된 도큐먼트의 전체 내용으로 검색하는 것에 대한 불편함을 살펴보았다. 임베드된 도큐먼트의 엘리먼트 키로 검색할 수 있는 방법은 우선 도큐먼트 임베드 시 구조를 array 형태로 구성한다:

선 다음과 array 형태의 도큐먼트를 임베드 한다:

db.schools.drop()

db.schools.insert(
	[
		{
			 _id: 1,
			 zipcode: 63109,
			 students: [
			              { name: "john", school: 102, age: 10 },
			              { name: "jess", school: 102, age: 11 },
			              { name: "jeff", school: 108, age: 15 }
			           ]
		},
		{
			 _id: 2,
			 zipcode: 63110,
			 students: [
			              { name: "ajax", school: 100, age: 7 },
			              { name: "achilles", school: 100, age: 8 },
			           ]
		},
		{
			 _id: 3,
			 zipcode: 63109,
			 students: [
			              { name: "ajax", school: 100, age: 7 },
			              { name: "achilles", school: 100, age: 8 },
			           ]
		},
		{
			 _id: 4,
			 zipcode: 63109,
			 students: [
			              { name: "barney", school: 102, age: 7 },
			           ]
		}
	]
)

다음과 같은 내용을 확인할 수 있을 것이다:

> db.schools.find() { "_id" : 1, "zipcode" : 63109, "students" : [ { "name" : "john", "school" : 102, "age" : 10 }, { "name" : "jess", "school" : 102, "age" : 11 }, { "name" : "jeff", "school" : 108, "age" : 15 } ] } { "_id" : 2, "zipcode" : 63110, "students" : [ { "name" : "ajax", "school" : 100, "age" : 7 }, { "name" : "achilles", "school" : 100, "age" : 8 } ] } { "_id" : 3, "zipcode" : 63109, "students" : [ { "name" : "ajax", "school" : 100, "age" : 7 }, { "name" : "achilles", "school" : 100, "age" : 8 } ] } { "_id" : 4, "zipcode" : 63109, "students" : [  {  "name" : "barney",  "school" : 102,  "age" : 7 } ] }

이제 "zipcode"가 63109인 것 중 "school"이 102와 요소 매칭되는 도큐먼트를 검색해 보자:

> db.schools.find( { zipcode: 63109 }, { students: { $elemMatch: { school: 102 } } } ) { "_id" : 1, "students" : [  {  "name" : "john",  "school" : 102,  "age" : 10 } ] } { "_id" : 3 } { "_id" : 4, "students" : [  {  "name" : "barney",  "school" : 102,  "age" : 7 } ] }

"zipcode"가 63109인 것은 _id: 1, _id: 3, _id: 4로 모두 3개이며, "school"이 102인 것은 _id: 1, _id: 4이므로 _id: 3에 대해서는 아무 내용이 표시되지 않았으며 나머지 두 도큐먼트에 대한 내용이 출력되었다.

이번에는 더 세밀하게 앞서 검색 조건에 덧붙여 나이(age)가 8살 이상인 학생이 포함된 도큐먼트를 검색해 보자:

> db.schools.find( { zipcode: 63109 }, { students: { $elemMatch: { school: 102, age: { $gt: 10} } } } ) { "_id" : 1, "students" : [  {  "name" : "jess",  "school" : 102,  "age" : 11 } ] } { "_id" : 3 } { "_id" : 4 }

검색조건에 맞는 올바른 검색결과를 얻을 수 있을 것이다.

마지막으로, "zipcode"가 63109인 것 중 "school"이 102와 요소 매칭되는 도큐먼트에 포함된 학생 중 나이가 어린 순으로 분류(sort)해 보자.

> db.schools.find({ zipcode: 63109 }, { students: { $elemMatch: { school: 102 } } }).sort( { "students.age": 1 } ) { "_id" : 3 } { "_id" : 4, "students" : [  {  "name" : "barney",  "school" : 102,  "age" : 7 } ] } { "_id" : 1, "students" : [  {  "name" : "john",  "school" : 102,  "age" : 10 } ] }


지금까지 임베드 된 도큐먼트에 대한 쿼리 방법에 대해 알아 보았다. 비정형구조의 데이터베이스(NoSQL)에서 도큐먼트가 임베드 되는 경우가 많으며 임베드 된 도큐먼트의 요소(elemenet)로 매칭 조건을 검색하는 일은 자주 발생하므로 반드시 익혀야 할 주제라 생각한다.

'Data Science > MongoDB' 카테고리의 다른 글

[MongoDB] Query / Cursors  (0) 2014.02.06
[MongoDB] Query / $where  (0) 2014.02.04
[MongoDB] Query / $slice  (0) 2014.02.01
[MongoDB] Query / $size  (1) 2014.02.01
[MongoDB] Query / $all  (0) 2014.02.01
Comments