게시글

5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭
강좌3 - MongoDB - 8년 전 등록

조회(Read 또는 Find)

안녕하세요. 이번 시간에는 CRUD에서 R을 담당하는 Read 기능을 알아보겠습니다. 지난 시간에 몬스터들을 넣었죠? 잘 있나 볼까요?

만약 지난 강좌 이후로 DB를 종료하셨다면 다시 mongod --dbpathmongo 명령어로 재실행합니다. 대표적인 조회 메소드로 find가 있습니다.

find

db.monsters.find({ }); // { 결과들 }
db.monsters.find({ name: 'Slime' }); // { 슬라임 }

find({ }) 또는 find()를 하면 컬렉션 내의 모든 다큐먼트들을 선택합니다. find({ name: 'Slime' })을 하면 다큐먼트 중에 name 필드가 Slime인 다큐먼트만 선택합니다.

결과는 다음과 같이 나옵니다.

일단 결과는 제대로 나오는 것 같습니다. 그런데 처음 보는 게 있습니다. 바로 _id 필드의 ObjectId(...)입니다. 분명 insert할 때는 넣은 적이 없는 것 같은 데 반환된 결과에는 있네요. 이게 몽고DB에서 자동으로 넣어주는 고유값입니다. 절대로 겹치지 않습니다. 이 세상에 절대가 어딨어! 하시는 분이 있을 수도 있겠네요. 그런데 첫 4바이트가 insert된 시간을 나타내기 때문에 겹치지 않습니다. 시간이 같을 수는 없겠죠?

find 메소드 안에 { } 부분에 구체적인 쿼리를 작성할 수 있습니다. 몽고DB는 다양한 옵션들을 제공합니다.

모두 다 일치해야 하는 경우는 그냥 쉼표로 구분합니다.

db.monsters.find({ name: 'Slime', hp: 25 }); // name이 Slime이고 hp가 25인 다큐먼트

한 가지만 일치해도 되는 경우는 $or을 사용합니다.

db.monsters.find({ $or: [{ name: 'Slime' }, { hp: 50 }] }); // name이 Slime이거나 hp가 50

숫자에 대한 비교 옵션도 있습니다. 큰 것은 $gt, 작은 것은 $lt, 크거나 같은 것은 $gte, 작거나 같은 것은 $lte 하면 됩니다.

db.monsters.find({ hp: { $lt: 100 } }); // hp가 100보다 다큐먼트

위와 같은 결과가 나왔다면 성공입니다! 쿼리의 옵션은 매우 많기 때문에 차차 알아가도록 하겠습니다.

findOne

단 하나만 찾고 싶을 때 사용합니다. find(...)[0]과도 같습니다. find 메소드로 찾은 것 중에 첫 번째 것을 선택하는 거죠.

db.monsters.findOne({ name: 'Slime' }); // { 슬라임 }

똑같이 슬라임에 대한 정보가 뜹니다. find 메소드처럼 구체적인 쿼리를 작성할 수 있습니다.

객체 조회

지금까지는 내부 객체를 쓰지 않았지만, 그것을 조회하고 싶은 경우를 알아봅시다. 다음과 같은 다큐먼트가 있다고 칩시다. 다큐먼트 안에 객체나 배열이 필드의 값으로 들어가도 상관 없습니다.

db:zero {
  _id: ObjectId('...'),
  profile: {
    name: 'Zero',
    birth: 1994
  },
  interest: ['javascript', 'mongodb']
}

이제 프로필 생일이 1994인 위의 문서를 찾아봅시다.

db.zero.find({ 'profile.birth': 1994 });

객체의 내부에 접근하듯이 .(점)으로 내부 속성을 지목하면 됩니다. 대신 따옴표로 묶어줘야 에러가 발생하지 않습니다.

배열 조회

이번에는 배열을 조회하는 방법입니다. 위의 다큐먼트를 그대로 사용합니다. mongodb를 요소로 갖고 있는 interest 필드를 찾으려면

db.zero.find({ interest: 'mongodb' });

하면 됩니다. 배열이라고 해서 특별히 다른 방법을 쓰거나 하진 않습니다.

투사(Projection)

투사(projection)이란 find와 findOne 메소드의 두 번째 인자로 넣어주는 겁니다. 번역할 마땅한 말이 없어서 그냥 투사라고 직역했습니다.

db.monsters.findOne({ name: 'Slime' }, { name: true, hp: true, _id: false});

하면 { name: 'Slime', hp: 25 } 라는 결과가 나옵니다. 이전에 쿼리했던 것과 비교하면 많이 짧아졌습니다. projection이 뭔지 짐작 가시나요? 바로 결과로 보여줄 것만 필터링하는 겁니다. name과 hp는 true고, _id는 false로 했더니 name과 hp만 반환되었습니다. 다른 필드는 기본값이 false이지만, _id는 기본값이 true이기 때문에 false를 직접 입력해줘야 나오지 않습니다.

projection이 유용한 경우는 민감한 데이터가 있을 경우입니다. 만약 댓글을 단 회원의 정보를 가져오고 싶은데 회원 정보를 통째로 가져오면 비밀번호나 개인 정보같은 게 모두 가져와지겠죠? 그럴 때 projection 객체를 사용해서 가져올 데이터만 걸러내는 겁니다. 제 홈페이지도 이렇게 가져올 것만 가져오고 있습니다. 보안은 안심하셔도 됩니다.

또한 한 가지 더 장점은 용량이 줄어듭니다. 게시글 리스트에서 게시글들을 모두 불러오면 용량이 어마어마합니다. 게시글 제목, 내용, 댓글까지 다 불러와지기 때문이죠. 이럴 때 제목만 불러오도록 하면 데이터를 아낄 수 있습니다.

다음 시간에는 Update 또는 Modify 기능을 알아봅시다.

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.
5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭

댓글

4개의 댓글이 있습니다.
4년 전
정말 감사합니다!!
7년 전
실수로 ctrl + c 를 눌러 나가버리니. save 했던 컬렌션까지 날아가 버리네요 ㅠ
7년 전
아마 명령프롬프트에서 복사 단축키는 Enter일 겁니다. 컬렉션은 안에 다큐먼트를 하나 이상 넣어야 완벽하게 저장됩니다.
7년 전
오? 다시 save 한 컬렉션은 잘 저장되어있군요. 그 전엔 무언가 실수를 했나봅니다..
7년 전
혹시 찾는 정보가 있을때 true를 반환하게 하는 건 어떻게하는지 아시나요?
7년 전
직접 true/false를 반환하는 것은 없는 걸로 알고요. db.콜렉션.find(조건).count() > 0으로 true/false를 받습니다.
7년 전
객체 생성이 없이 객체 조회로 넘어가셨어요
7년 전
이전 강좌에 Slime과 Skeleton 객체 생성하는 부분이 있습니다.