2011. 9. 19. 18:56
[mongodb] Querying
2011. 9. 19. 18:56 in Research/mongodb
* find 소개
db.a.find()
db.a.find({"k":"1", "b":2})
db.a.find({}, {"a":1, "b":1})
db.a.find({}, {"a":1, "_id":0})
* 제약 사항
; find에 사용되는 query value 값은 상수여야 한다.
db.a.find({"a":1})
{"a":1}
상황에서,
var node={"query":1}
var def=1
db.a.find({"a":node.query})
{"a":1}
db.a.find({"a":this.def})
{"a":1}
와 같이 query는 잘 되었다.
여하튼, query value 값은 상수여야 하는 제약 조건을 잘 지켜야 한다.
그리고,
var test={"keyname":"a"}
db.a.find({"keyname.a":1})
는 당연히 query되지 않고,
db.a.find({keyname.a:1})
하면 오류가 발생한다.
즉, key 이름도 당연히 상수여야 할 듯하다.
* query 조건들
; comparision operator
db.a.find({"num":{"$gte":2, "$lte":5}})
start = new Date("01/01/2007")
db.a.find({"registered":{"$lt":start}})
db.a.find({"name":{"$ne":"joe"}})
; OR query
; $not
; conditions 규칙
* type 지정 query (type-specific queries)
; null
; regular expression
; array query하기
$size
$slice
; embeded document query 하기
* $where query
key/value pair로 query하는것은 표현력이 좋으나, 표현하기 힘든 query도 존재한다.
JavaScript와 함께 사용하여 query를 좀더 유연하게 하는것이 "$where"이다.
* cursor
; skip의 양 줄이기
이런경우, query만 사용하여 skip없이 만들수 있다.
var page1 = db.a.find().sort({"a":-1}).limit(100)
var latest = null;
// display first page
while (page1.hasNext()) {
latest = page1.next();
display(latest);
}
; random 문서 구하기
혹은 ensureIndex를 이용하기도 한다.
; 일관된 결과 만들기
while (cursor.hasNext()) {
var doc = cursor.next();
doc = process(doc);
do.foo.save(doc);
즉, 모든 document를 process하고, save한다.
그런데, 만일,
1 -> 2 -> 3 -> ... 과 같은 순서의 document가 진행될 때,
2번 document를 process하여 저장하는데,
만일 db의 크기가 커지면 relocate가 발생할 수 있다.
그러면,
1 -> () -> 3 -> ... -> 2
와 같이 되는데, 그러면 위 while loop에서 문제가 생길 수 있다.
db.a.find()
; collection a에 있는 모든 document 검색
db.a.find({"k":"1", "b":2})
; collection a에서 k=1, b=2인 모든 document 검색
(condition AND condition AND ...)
(condition AND condition AND ...)
db.a.find({}, {"a":1, "b":1})
; a, b key만 리턴한다. (_id key는 항상 리턴된다)
db.a.find({}, {"a":1, "_id":0})
; a key만 리턴된다. _id key는 제외된다.
* 제약 사항
; find에 사용되는 query value 값은 상수여야 한다.
db.a.find({"a":1})
{"a":1}
상황에서,
var node={"query":1}
var def=1
db.a.find({"a":node.query})
{"a":1}
db.a.find({"a":this.def})
{"a":1}
와 같이 query는 잘 되었다.
여하튼, query value 값은 상수여야 하는 제약 조건을 잘 지켜야 한다.
그리고,
var test={"keyname":"a"}
db.a.find({"keyname.a":1})
는 당연히 query되지 않고,
db.a.find({keyname.a:1})
하면 오류가 발생한다.
즉, key 이름도 당연히 상수여야 할 듯하다.
* query 조건들
; comparision operator
$lt, $lte, $gt, $gte --> <, <=, >, >=
db.a.find({"num":{"$gte":2, "$lte":5}})
start = new Date("01/01/2007")
db.a.find({"registered":{"$lt":start}})
db.a.find({"name":{"$ne":"joe"}})
; OR query
$in - 단일 key에 대한 여러가지 값 (<-> $nin)
$or - 보다 일반적
$or - 보다 일반적
db.a.find({"answer":{"$in":[1,2,4]}})
db.a.find({"answer":{"$nin":[3,5]}})
db.a.find({"$or":[{"attr":1}, {"attr2":2}]})
db.a.find({"answer":{"$nin":[3,5]}})
db.a.find({"$or":[{"attr":1}, {"attr2":2}]})
; $not
db.a.insert({"a":1})
...
db.a.insert({"a":13})
db.a.find({"a":{"$mod":[5,1]}})
{"a":1}
{"a":6}
{"a":11}
...
db.a.insert({"a":13})
db.a.find({"a":{"$mod":[5,1]}})
{"a":1}
{"a":6}
{"a":11}
$mod는 나머지 연산자
db.a.find({"a":{"$not":{$mod":[5,1]}}})
{"a":2}
... => "a"는 2,3,4,5,6,7,8,9,10,12,13 이 리턴
{"a":2}
... => "a"는 2,3,4,5,6,7,8,9,10,12,13 이 리턴
; conditions 규칙
$-prefixed key는 각각 적절한 다른 위치를 가진다.
; inner(안쪽) document - $lt, ...
; outer(바깥쪽) document - $inc, ...
; inner(안쪽) document - $lt, ...
; outer(바깥쪽) document - $inc, ...
db.a.find({"a":{"$lt":3, "$gt":2}})
{"$inc":{"age":1}, "$set":{age:40}}
{"$inc":{"age":1}, "$set":{age:40}}
* type 지정 query (type-specific queries)
; null
db.a.find({"a":null})
; 그 자체로 match되고, 또한 "does not exist"(=> $exists)도 match 한다.
만약, "a":null 문서가 있다면 -> 그것을 리턴
만약, "a" key가 문서에 없다면 -> 모두 리턴
; 그 자체로 match되고, 또한 "does not exist"(=> $exists)도 match 한다.
만약, "a":null 문서가 있다면 -> 그것을 리턴
만약, "a" key가 문서에 없다면 -> 모두 리턴
db.a.find({"a":{"$in":[null], "$exists":true}})
; regular expression
db.a.find({"name":/joe/i})
; array query하기
db.a.insert({"a":[1,2,3]})
db.a.find({"a":2})
{a:[1,2,3]}
db.a.find({"a":2})
{a:[1,2,3]}
$all
db.a.insert({"a":1, "b":[1,2,3]})
db.a.insert({"a":2, "b":[2,3,4]})
db.a.insert({"a":3, "b":[3,4,5]})
db.a.find({"b":{$all:[2,3]})
{a:1, b:[1,2,3]}
{a:2, b:[2,3,4]}
db.a.insert({"a":2, "b":[2,3,4]})
db.a.insert({"a":3, "b":[3,4,5]})
db.a.find({"b":{$all:[2,3]})
{a:1, b:[1,2,3]}
{a:2, b:[2,3,4]}
db.a.find({"b.2", 3})
{a:1, b:[1,2,3]}
; 0-based index로 find 가능
{a:1, b:[1,2,3]}
; 0-based index로 find 가능
$size
array의 크기 비교
$gt등과 조합 못함
db.a.find({"b":{"$size":3}})
$gt등과 조합 못함
db.a.find({"b":{"$size":3}})
$slice
array key의 subset 리턴.
; embeded document query 하기
; document 전체를 query하는 방법과 개별 key/value pair로 query하는 방법이 있다.
db.a.insert({"a":{"q":1, "w":2}})
db.a.find({"a":{"q":1, "w":2}})
{"a":{"q":1, "w":2}}
db.a.find({"a":{"q":1}})
와 같이 일반 key/value로 하면 query 결과가 나오지 않는다.
이를 방지하려면 다음과 같이 하라.
db.a.find({"a.q":1}})
{"a":{"q":1, "w":2}}
db.a.find({"a":{"q":1, "w":2}})
{"a":{"q":1, "w":2}}
db.a.find({"a":{"q":1}})
와 같이 일반 key/value로 하면 query 결과가 나오지 않는다.
이를 방지하려면 다음과 같이 하라.
db.a.find({"a.q":1}})
{"a":{"q":1, "w":2}}
다음과 같은 document가 있다고 하자.
{
"arr" : [
{
"a" : 1,
"b" : 1,
"c" : 1
},
{
"a" : 2,
"b" : 2,
"c" : 2
}
]
}
db.a.find({"arr":{"a":1, "b":1}) 하면 결과가 없다. c 조건이 없기 때문이다.
db.a.find({"arr":{"a":1, "b":{"$gte":1}}}) 하면 결과가 없다.
db.a.find({"arr.a":1, "arr.b":2}) 하면 query된다. a=1,b=2인 내용이 없지만 query된다.
db.a.find({"arr.a":1, "arr.b":3}) 하면 결과가 없다.
==> 즉, .로 사용된 key가 2개 이상인 경우, 내부 element 중 모두 충족하면 query된다.
{
"arr" : [
{
"a" : 1,
"b" : 1,
"c" : 1
},
{
"a" : 2,
"b" : 2,
"c" : 2
}
]
}
db.a.find({"arr":{"a":1, "b":1}) 하면 결과가 없다. c 조건이 없기 때문이다.
db.a.find({"arr":{"a":1, "b":{"$gte":1}}}) 하면 결과가 없다.
db.a.find({"arr.a":1, "arr.b":2}) 하면 query된다. a=1,b=2인 내용이 없지만 query된다.
db.a.find({"arr.a":1, "arr.b":3}) 하면 결과가 없다.
==> 즉, .로 사용된 key가 2개 이상인 경우, 내부 element 중 모두 충족하면 query된다.
만일, array 내부의 document에 a=1, b=2를 지원하는 document가 있는지 query해야 한다면?
db.a.find({"arr":{"$elemMatch":{"a":1,"b":2}}})
하면 내용이 없다.
위 예에서 a:1,b:2,c:3을 추가하면 query된다.
db.a.find({"arr":{"$elemMatch":{"a":1,"b":2}}})
하면 내용이 없다.
위 예에서 a:1,b:2,c:3을 추가하면 query된다.
* $where query
key/value pair로 query하는것은 표현력이 좋으나, 표현하기 힘든 query도 존재한다.
JavaScript와 함께 사용하여 query를 좀더 유연하게 하는것이 "$where"이다.
db.a.insert({"a":1, "b":2, "c":3})
db.a.insert({"a":11,"q":9, "w":9})
db.a.find({"$where":"this.b+this.c==5"})
{"a":1, "b":2, "c":3}
db.a.insert({"a":11,"q":9, "w":9})
db.a.find({"$where":"this.b+this.c==5"})
{"a":1, "b":2, "c":3}
db.a.find({"$where":function(){return this.b+this.c==5}})
{"a":1, "b":2, "c":3}
{"a":1, "b":2, "c":3}
보통의 query 보다 느리다.
각각의 document는 BSON -> JavaScript Object로 변환된다.
각각의 document는 BSON -> JavaScript Object로 변환된다.
복잡한 query를 할 수 있는 다른 방법중 하나는 MapReduce이다.
* cursor
for (i=0; i<100; i++) { db.a.insert({x:i}); }
var cursor = db.a.find();
; limit, skip, sort
var cursor = db.a.find();
; limit, skip, sort
db.c.find().limit(3) - 3개의 결과만.
db.c.find().skip(3) - 3개 다음으로.
db.c.find().sort({a:1}) - a key로 1=ascending sort
db.c.find().sort({a:-1}) - a key로 -1=decending sort
db.c.find().skip(3) - 3개 다음으로.
db.c.find().sort({a:1}) - a key로 1=ascending sort
db.c.find().sort({a:-1}) - a key로 -1=decending sort
; skip의 양 줄이기
skip에는 작은 값이 좋다. 만약 result가 많다면, skip은 느리며, 이는 기피 대상이다.
; skip 없이 page 나누기
; skip 없이 page 나누기
var page1 = db.a.find(...).limit(100)
var page2 = db.a.find(...).skip(100).limit(100)
var page3 = db.a.find(...).skip(200).limit(100)
var page2 = db.a.find(...).skip(100).limit(100)
var page3 = db.a.find(...).skip(200).limit(100)
이런경우, query만 사용하여 skip없이 만들수 있다.
var page1 = db.a.find().sort({"a":-1}).limit(100)
var latest = null;
// display first page
while (page1.hasNext()) {
latest = page1.next();
display(latest);
}
// get next page
var page2 = db.a.find({"a":{"$gt":latest.date}});
page2.sort({"a":-1}).limit(100);
var page2 = db.a.find({"a":{"$gt":latest.date}});
page2.sort({"a":-1}).limit(100);
==> skip 없이 구현되었다.
; random 문서 구하기
// skip 사용 (사용하지 말 것)
var toal = db.a.count()
var random = Math.floor(Math.random()*total)
db.a.find().skip(random).limit(1)
var toal = db.a.count()
var random = Math.floor(Math.random()*total)
db.a.find().skip(random).limit(1)
// skip 없이 사용
db.a.insert({"a":1, "random":Math.random()})
db.a.insert({"a":2, "random":Math.random()})
db.a.insert({"a":3, "random":Math.random()})
var random = Math.random()
result = db.a.findOne({"random":{"$gt":random}})
if (null == result)
{
result = db.a.findOne({"random":{"$lt":random}})
}
db.a.insert({"a":1, "random":Math.random()})
db.a.insert({"a":2, "random":Math.random()})
db.a.insert({"a":3, "random":Math.random()})
var random = Math.random()
result = db.a.findOne({"random":{"$gt":random}})
if (null == result)
{
result = db.a.findOne({"random":{"$lt":random}})
}
혹은 ensureIndex를 이용하기도 한다.
; 일관된 결과 만들기
cursor = db.foo.find();
while (cursor.hasNext()) {
var doc = cursor.next();
doc = process(doc);
do.foo.save(doc);
즉, 모든 document를 process하고, save한다.
그런데, 만일,
1 -> 2 -> 3 -> ... 과 같은 순서의 document가 진행될 때,
2번 document를 process하여 저장하는데,
만일 db의 크기가 커지면 relocate가 발생할 수 있다.
그러면,
1 -> () -> 3 -> ... -> 2
와 같이 되는데, 그러면 위 while loop에서 문제가 생길 수 있다.
이를 해결하기 위해서는 "$snapshot" option이 필요하다.
'Research > mongodb' 카테고리의 다른 글
[mongodb] Advanced topics (0) | 2011.09.23 |
---|---|
[mongodb] Aggregation (MapReduce) (0) | 2011.09.22 |
[mongodb] Indexing (0) | 2011.09.22 |
[mongodb] Creating, Updating, and Deleting Documents (0) | 2011.09.15 |
mongodb, the definitive guide (o'relly, kristina chodorow, michael dirolf) (0) | 2011.09.15 |