반응형

이번에는 몽고DB에서 데이터 조회를 해볼 것이다.

find는 RDB(MySQL과 같은...)에서의 SELECT 같은 역할을 한다.

find에도 옵션이 상당히 많기 때문에 여기서는 최소한의 기능을 알아볼 예정이다.

일단 find를 사용하기 전에 임시로 아래와 같이 데이타를 등록해놓았다.

 

db.temps.insert({name: '홍길동', age: 20, gender: '남'});
db.temps.insert({name: '최길동', age: 21, gender: '남'});
db.temps.insert({name: '김길동', age: 22, gender: '여'});
db.temps.insert({name: '윤길동', age: 23, gender: '여'});
db.temps.insert({name: '박길동', age: 24, gender: '남'});
db.temps.insert({name: '고길동', age: 25, gender: '남'});
db.temps.insert({name: '모길동', age: 26, gender: '여'});
db.temps.insert({name: '공길동', age: 27, gender: '남'});
db.temps.insert({name: '구길동', age: 28, gender: '남'});
db.temps.insert({name: '정길동', age: 29, gender: '남'});
db.temps.insert({name: '서길동', age: 30, gender: '남'});

 

위와 같이 데이타 삽입을 하고 아주 간단하게 다음과 같이 조회해볼 수 있다.

 

temps 컬렉션의 모든 항목이 표시된다.

MySQL로 예를 들면 'SELECT * FROM temps' 와 같은 명령과 동일하다고 보면 된다.

그리고 위의 경우 데이타가 깔끔하게 보여지지만 필드가 많아질 수록 제대로 정렬이 안되어서 보기 불편할 수가 있다. 그럴 때는 아래와 같이 find() 뒤에 .pretty()를 붙여주면 다음과 같이 데이터를 더 정리된 형태로 볼 수 있다.

 

이와 같이 잘 정렬되어 보여진다.

이제 다음으로는 기본적인 조건 옵션을 붙여보도록 할 것이다.(MySQL의 WHERE절과 같은)

 

도큐먼트 조회시 조건 걸기

이름이 '김길동'인 사람을 조회해보도록 하겠다.

db.temps.find({name: '김길동'});

위와 같이 단순하다. find() 명령안에 { } 중괄호로 원하는 조건을 감싸주기만 하면 된다.

 

만약 조건을 더 붙이고 싶다면 콤마(,)로 구분하여 뒤에 연결시켜주면 된다.

db.temps.find({name: '김길동', age: 22});

예를 들어, 위와 같은 명령이라면 name이 김길동이고 age가 22인 도큐먼트를 가져오게 된다.

 

도큐먼트 조회시 숫자를 비교하는 조건 걸기

조회할 경우 특정 데이타와 완전히 동일한지만 비교할 수도 있지만, 위의 데이타로 예를 들면 20~25세의 도큐먼트만

가져오는 등의 숫자 비교 조건을 걸 수도 있다.

 

MySQL의 경우 'SELECT * FROM temps WHERE age >= 20 AND age <= 25' 이런 형태로 단순하게 부호를 이용해서

비교가 가능하지만 MongoDB에서는 용법이 조금 다르다.

MongoDB에서는 다음과 같이 사용할 수 있다.

 

db.temps.find({age: {$gte: 20, $lte: 25}});

이와 같이 조건이 적용된 것을 확인할 수 있다.

위 명령을 분석해보면 $gte, $lte 라는 것들을 연산자(operator)라고 한다.

기본적으로 필드가 앞에 있고 필드 뒤에 연산자를 중괄호{}로 감싸서 사용하게 된다.

 

$gte는 greater than or equals이란 의미로 '같거나 크면'이라는 조건의 의미를 갖는다.

$lte는 less than or equals이란 의미로 '같거나 작으면'이라는 조건의 의미를 갖는다.

이외에 다양한 연산자가 존재한다.

 

$gt : 주어진 값보다 큰 경우

$lt : 주어진 값보다 작은 경우

$eq : 주어진 값과 일치하는 경우

$ne : 주어진 값과 일치하지 않는 경우

$in : 주어진 배열 안에 속하는 값

$nin : 주어진 배열 안에 속하지 않는 값

 

위는 비교 연산자이고, 그 외에 논리 연산자, 문자열 연산자 등 다양한 연산자가 따로 존재한다. 

그것은 각 연산자 사용시에 다시 알아보도록 하겠다.

 

도큐먼트 조회시 정렬하기

가져온 데이타들을 소팅할 수 있는 방법을 알아볼 것이다.

위에서 insert한 데이타들을 기준으로 age 필드의 데이타를 내림차순으로 정렬해보려 한다.

db.temps.find().sort({age: -1});

아주 간단하게 정렬이 되었다.

find()뒤에 sort()명령을 붙여줄 수 있고 중괄호 안에 원하는 정렬 기준을 지정해주면 된다.

age: -1는 age 필드를 내림차순으로 정렬한다는 의미이다.

-1은 내림차순이지만 오름차순으로 정렬하고 싶다면 {age: 1}과 같은 형태로 사용하면 된다.

이 때 .sort() 명령 뒤에 .pretty()를 붙여서 더 정리된 형태로 표시할 수도 있다.

 

도큐먼트 조회시 특정 개수만 표시하기, 특정 위치의 데이타 가져오기

데이타 수량이 너무 많거나 페이지네이션 구현 등을 위해 특정 개수만 표시하고 싶을 때가 있다.

이 때는 .limit()이라는 명령을 사용할 수 있다.

 

db.temps.find().limit(1);

이와 같이 가져올 데이타의 상위 1개의 데이타만 가져오게 된다.

페이지네이션 구현을 위해 많이 사용하게 된다. 페이지네이션 구현시에는 특정 개수만 가져오는 것도 필요하지만,

특정 위치의 도큐먼트를 가져오는 것도 필요하다.

이 때는 .skip()이라는 명령을 사용할 수 있다.

 

db.temps.find().skip(2).limit(2);

조회할 데이타의 2개 뒤의 데이타들 중 2개만 가져오는 명령이다.

이를 통해서 페이지네이션을 구현할 수 있다.

 

여기까지 find의 기본적인 내용들을 다루어보았고, 다음에는 여기서 설명하지 않았던 다른 연산자들에 대해서도

알아보려 한다.

반응형
반응형

이번에는 몽고DB에서 데이타를 삭제하는 방법을 알아볼 것이다.

remove는 단일 혹은 다수 삭제가 모두 가능하고 deleteOne은 단일 삭제만 deleteMany는 다수 삭제만

가능하다. MongoDB 3.2버전부터 remove 대신 deleteOne, deleteMany로 대체되었다.

 

1. 삭제(remove)

MySQL에서 'DELETE FROM' 과 매칭되는 명령이다.

insert 혹은 update명령과 비슷한 형태로 사용하게 되는데 단순히 삭제할 조건만 넣어주면 된다.

먼저 위와 같이 데이터를 넣어놓고, 이름이 "최길동"인 사용자를 삭제해보도록 하겠다.

db.users.remove({name: "최길동"});

실행 결과

정상적으로 삭제되었으며, 조건에 따라 단일 삭제가 될 수도 있고 다수 삭제가 될 수도 있다.

예를 들어, 나이가 27살 이상인 사용자를 삭제하고 싶을 경우 다음 명령을 사용한다.

db.users.remove({age: {$gte: 27}});

($gte 연산자는 'greater than or equal'의 약자로 '같거나 크면'의 의미를 갖는다.

 여러 연산자에 대해서는 다음 포스팅에서 다뤄볼 예정이다.)

이와 같이 3개가 삭제되었다는 메세지가 나오며, 조회해보니 정상적으로 삭제된 것을 확인할 수 있다.

remove()의 사용법을 알아보았다. 하지만 몽고3.2 이후에는 deleteOne, deleteMany로 대체되었으니,

remove의 사용은 자제하는 것이 좋다.

 

2. 단일 삭제(deleteOne)

지난번 포스팅에서 설명했던 insertOne, insertMany, updateOne, updateMany와 같은 형태로 용법이 비슷하고,

바로 위에 설명한 remove() 용법이 단일, 다수 삭제 기능으로 분리된 것 뿐이기에 간단하게 설명하고 넘어갈 것이다.

 

db.users.deleteOne({name: "최길동"});

'최길동'이라는 사용자 도큐먼트를 삭제하는 명령이다.

(최길동이라는 사용자가 두명이면 가장 처음의 '최길동' 사용자 도큐먼트만 삭제된다.)

 

db.users.deleteOne({});

처음 도큐먼트 한개를 삭제하는 명령이다.

 

db.users.deleteOne({age: {$gte: 27}});

age 필드가 27 이상의 도큐먼트 중 처음 도큐먼트 한개를 삭제하는 명령이다.

 

3. 다수 삭제(deleteMany)

조건에 해당하는 데이타를 모두 삭제할 때 사용한다.

 

db.users.deleteMany({name: "최길동"});

'최길동'이라는 사용자 도큐먼트를 모두 삭제한다.

 

db.users.deleteMany({});

users 컬렉션의 모든 도큐먼트를 삭제하는 명령이다.

 

db.users.deleteMany({age: {$gte: 27}});

age 필드가 27 이상의 도큐먼트를 모두 삭제한다.

 

 

반응형
반응형

이번에는 몽고DB에서 데이타를 수정하는 방법을 알아본다.

update 또한 insert와 마찬가지로 함수 형태가 크게 세개로 구성된다.

update 명령은 단일 도큐먼트 혹은 다수의 도큐먼트를 수정할 수 있고 updateOne은 단일 도큐먼트만,

updateMany는 다수의 도큐먼트만 수정 가능하다.

MongoDB 3.2버전 이후부터는 update() 함수 대신 updateOne()과 updateMany() 함수를 사용하기를 권장한다.

 

1. 수정(update)

데이타를 수정할 때 사용하는 명령이며, MSQL의 update와 매칭되는 명령이다.

insert 명령과 마찬가지로 JSON 형태로 데이터를 수정할 수 있다.

 

위와 같은 데이터가 있다고 가정해보자.

name이 '홍길동'인 age의 값 20을 23으로 변경하고자 하면 아래와 같이 명령을 실행할 수 있다.

db.users.update({name: '홍길동'}, {$set:{age: 23}});

 

위와 같이 정상적으로 입력된 것을 확인할 수 있다.

데이터를 조회해보니 age값이 20에서 23으로 변경되었다.

MongoDB에서 update명령을 사용하여 특정 필드의 값을 변경할 때는 $set 연산자를 사용하여야 한다.

만약 사용하지 않는다면 어떻게 될까?

 

$set 연산자를 제거하고 나이를 25살로 변경하여 입력해보았더니 위와 같은 결과가 나왔다.

$set 연산자를 사용하지 않을 경우 입력한 데이터 자체를 통째로 덮어버리게 된다.

즉, 기존에 존재하던 name 필드까지 사라져버리는 것이다.

그렇기에 update 명령 사용시에는 반드시 주의해야 한다. $set 사용하는 것을 실수해서 

다른 필드를 날려버리는 경우가 종종 발생할 수 있다.

 

update 명령은 단일 도큐먼트도 수정 가능하지만 다수의 도큐먼트도 수정 가능하다.

다수의 도큐먼트 수정시에는 multi 옵션을 사용하여 수정할 수 있다.

먼저 테스트를 위해 위와 같이 데이터를 준비하였다.

위 두 데이터 전체의 나이를 25로 변경해보도록 하겠다.

db.users.update({}, {$set: {age: 25}}, {multi: true});

앞의 조건 {}은 전체 필드를 수정하겠다는 의미이다.

조회해보면 다음과 같은 결과가 나온다.

age 필드가 모두 정상적으로 25로 변경되었다.

만약 multi 옵션을 사용하지 않는다면 기본적으로 단일 도큐먼트 수정이 되기 때문에 가장 처음 데이터만 변경이 된다.

 

2. 단일 데이터 수정(updateOne)

update와 사용법은 동일하다. 단지, 단일 도큐먼트만 수정될 뿐이다.

db.users.updateOne({name: '홍길동'}, {$set: {age: 25}});

이와 같이 명령을 실행하면 name 필드가 '홍길동'인 age 값을 25로 변경한다.

완전히 동일하다.

 

3. 다수 데이터 수정(updateMany)

update의 multi 옵션을 자동으로 사용해준 명령이라고 보면 된다.

위의 두개 도큐먼트에 대한 age를 모두 27로 변경해보겠다.

db.users.updateMany({}, {$set: {age: 27}});

multi 옵션 없이 조건에 해당하는 모든 필드가 알아서 수정이 된다.

updateOne과 updateMany은 update 명령에 비해 좀 더 명시적으로 업데이트되었다고 보면 될 것 같다.

 

반응형
반응형

 

몽고DB에서 데이터 삽입하는 방법에 대해 알아보도록 할 것이다.

데이터를 삽입하는 방식에는 크게 세가지가 있다.

insert 명령, insertOne명령, insertMany명령인데, insert의 경우 단일 도큐먼트 혹은 다수 도큐먼트 모두 삽입이

가능하며, insertOne의 경우 단일 도큐먼트만, insertMany는 다수 도큐먼트만 삽입할 수 있다.

 

1. 삽입(insert)

DB에 데이터를 삽입할 때 사용하는 명령어이다. MySQL의 insert와 매칭되는 명령인데,

MySQL의 경우 각 필드에 데이터를 입력시켜주는 반면 몽고DB에서는 데이터를 도큐먼트 단위로 입력시켜주게 되며,

도큐먼트는 JSON 형태의 데이터로 구성된다.

 

users 컬렉션에 아래와 같이 데이터를 입력시켜볼 수 있다.

db.users.insert({

    name: '홍길동',

    age: 20,

});

위와 같이 입력이 완료되었고, find() 명령을 통해 입력된 데이타를 확인할 수 있다.

db.users.find();

위는 users 컬렉션에 있는 모든 도큐먼트를 조회한 결과이다.

insert() 명령으로 넣은 JSON 데이타가 그대로 들어가있다.

그런데 _id라는 필드는 입력하지 않았는데 자동으로 생겨버렸다.

이 필드는 MySQL에서 Primary key와 같은 역할을 하는 필드라고 보면 된다.

중복을 허용하지 않는 고유의 값이며, 기본적으로 인덱스가 걸려있기 때문에 해당 필드로 조회시 검색 성능은 보장된다. 

 

insert를 이용하여 다수의 데이타를 한번 삽입해보도록 하겠다.

다수의 데이타 삽입시에는 배열을 사용한다.

db.users.insert([
{
    name: '최길동',
    age: 21,
},
{
    name: '박길동',
    age: 22,
},
]);

위와 같이 대괄호 []를 통해 다수의 데이터를 삽입할 수 있다.

정상적으로 다수의 데이타가 입력된 것을 확인할 수 있다.

 

2. 단일 데이터 삽입(insertOne)

insertOne은 단일 도큐먼트를 삽입하는 명령이다.

몽고 3.2버전 이후에 추가된 명령이며, insert를 대체하기 위해 만들어졌다고 한다.

insert()명령과 사용법은 동일하며, 배열 형태로 다수의 데이터를 삽입하는 것은 insertMany명령을 이용해야 한다.

db.users.insertOne({
    name: '홍길동',
    age: 20,
});

아래와 같이 조회하면 정상적으로 데이타가 삽입된 것을 확인할 수 있다.

 

3. 다수 데이터 삽입(insertMany)

insertMany은 다수의 도큐먼트를 한번에 삽입하는 명령이다.

insertOne과 같이 몽고 3.2버전 이후에 추가된 명령이다.

다수 데이터 삽입이므로 배열 형태로 삽입하며 아래와 같이 명령을 사용할 수 있다.

db.users.insertMany([
{
    name: '최길동',
    age: 21,
},
{
    name: '박길동',
    age: 22,
}

]);

정상적으로 삽입이 완료되었다.

 

몽고3.2버전 이후에는 insertOne(), insertMany() 명령을 사용을 권장하므로, insert() 명령 사용은 자제하는 것이 좋을 것으로 보인다.

반응형
반응형

MongoDB를 사용할 때 기본이라고 할 수 있는 데이타베이스와 컬렉션에 대해서 알아보고 만들어볼 것이다.

Database라는 것은 MongoDB에서 사용하는 데이타베이스의 가장 큰 단위이다.

Collection은 Database의 하위에 속하는 개념이다.

Field는 모여서 하나의 컬렉션을 구성하게 된다.

Document는 위의 항목으로 구성된 데이타베이스의 실제 데이타이다.

 

예를 들어서 설명해보겠다.

 

내가 쇼핑몰을 만들기 위해 DB를 구축해야 하는 상황이고, 쇼핑몰 이름은 신사 쇼핑몰이다.

신사 쇼핑몰 내에서 관리되어야 할 DB에는 유저 정보, 상품 정보, 결제 정보, 문의 내용 등 여러가지가 있다.

여기서 신사 쇼핑몰 이 자체가 데이타베이스가 되고, 유저정보, 상품 정보 등의 내용은 컬렉션이 된다.

그리고 유저 정보 내의 이름, 생년월일, 전화번호 등의 정보는 필드가 된다.

유저정보에 이름, 생년월일, 전화번호 등의 모든 필드를 채운 완성된 하나의 정보가 들어가면 도큐먼트가 된다.

 

한가지 더 예를 들어서 학원을 운영하는 프로그램을 개발하는데 여기에 구축해야 될 DB를 만든다고 하면,

학원은 데이타베이스가 되고, 학원 내에 필요한 정보들인 선생님 정보, 학생 정보, 과목 정보 등이 컬렉션이 된다.

여기서도 선생님 정보를 예로 들면 선생님 이름, 가르치는 과목 등의 정보가 필드가 된다.

이 필드들이 모두 채워진 하나 이상의 데이타를 도큐먼트라 한다.

 

위의 예로 어느정도 개념은 잡혔으리라 생각한다.

 

MySQL과 같은 RDB를 사용해본 개발자라면 ,

MySQL의 Database = MongoDB의 Database

MySQL의 Table = MongoDB의 Collection,

MySQL의 Column = MongoDB의 Field,

MySQL의 Row = MongoDB의 Document로 보면 된다.

 

이제 각 항목들을 만들어보고 지워보는 등의 작업을 해볼 것이다.

 

1. Database 생성

> use shinsa

  shinsa 라는 이름으로 DB를 생성한다.

 

2. Collection 생성 (대소문자 구분에 주의한다.)

> db.createCollection("users");

  users 라는 이름으로 컬렉션을 생성한다. 

  위에서 shinsa라는 DB 생성 과정을 거쳤으므로 shinsa DB 내에 users 컬렉션이 생성되는 것이다.

 

3. Collection 생성 확인

> show collections;

 

4. Database 생성 확인

> show databases;

 

 

위와 같이 users 컬렉션과 shinsa 데이타베이스가 생성된 것을 확인할 수 있다.

 

5. users 컬렉션에 유저 도큐먼트를 생성한다.

> db.users.insert({"name": "홍길동", "age": 20, "gender": "man"});

  name 필드, age 필드, gender 필드로 구성된 users 컬렉션에 해당 도큐먼트를 생성하는 명령이다.

 

6. users 컬렉션의 생성한 데이타를 확인한다.

> db.users.find();

위와 같이 도큐먼트가 추가된 것을 확인할 수 있다.

여기까지가 데이타베이스를 구성하고 조회하는 가장 기본적인 내용이다.

실제로 MongoDB를 실무에서 사용하게 될 때 이런 식으로 DB를 구성하게 될 것이다.

(물론 이 외에 다양한 고급 기능들이 존재하지만 그것은 나중에 다루도록 한다.)

 

7. 만들어진 컬렉션을 삭제한다.

> db.users.drop(); 

  show collections; 명령으로 users 컬렉션이 삭제된 것을 확인할 수 있다.

 

8. 만들어진 데이타베이스를 삭제한다.

> use shinsa;

> db.dropDatabase();

  db.dropDatabase() 명령만 사용하여 바로 제거해도 되지만, 실수로 다른 DB를 선택해놓고 삭제하는 것을 방지 하기 위해 use 데이타베이스 명령으로 확실히 데이타베이스를 설정해주고 삭제하도록 하는 것이 좋다.

  이제 show databases; 명령으로 shinsa 데이타베이스가 삭제된 것을 확인할 수 있다.

 

반응형
반응형

얼마 전 황당한 일을 겪었다.

로컬 PC에 몽고 데몬을 올려놓고 해당 DB를 연동하여 테스트 서버로 쓰고 있었는데,

갑자기 잘 되던 테스트 페이지에 로그인이 안되며 계정이 없다는 오류를 띄우는 것이었다.

바로 로컬 몽고DB에 접속하여 DB를 확인해보았다.

 

데이타베이스 목록을 확인해보니, 내가 만들어놓은 데이타베이스는 없어지고 웬 이상한 DB가 들어있었다.

느낌이 불길했다.

 

해당 DB를 들어가서 컬렉션 목록을 확인했다.

읽어보라고 떡하니 'README'라는 컬렉션이 만들어져 있었고 바로 내용을 확인해보았다.

 

"All your data is a backed up. You must pay 0.04 BTC to 1FYqD4YtPpcnHyyMiFFigG53s51dcb6xx1 48 hours for recover it. After 48 hours expiration we will leaked and exposed all your data. In case of refusal to pay. we will contact the General Data Protection Regulation, GDPR and notify them that you store user data in an open form and is not safe. Under the rules of the law, you face a heavy fine or arrest and your base dump will be dropped from our server! You can bitcoin here, does not take much time to buy https://localbitcoins.comwith this guide https://localbitcoins.com/guides/how-to-buy-bitcoins After paying write to me in the mail with your DB IP: recoverbase@cock.li and you will receive a link to download your database dump."

아뿔싸... 내가 그 말로만 듣던 랜섬웨어를 당했다니... 분하기도 하고 치욕스럽기까지 했다.

내용은 대충 이렇다. 0.04 비트코인을 지불하면 잃어버린 데이타를 복구해주겠다는 것이고, 

이것을 무시하면 GDPR에 신고하여 법적인 책임을 물게 하겠다는 것이다.

 

개인정보보호정책에 의해 개인의 정보는 안전하게 관리되어야 하므로 이를 허술하게 관리한 대가로 책임을 묻게 될 수 있는 것이다.

 

일단 날아간 데이타는 없으면 귀찮아지기는 하겠지만, 크리티컬한 수준은 아니었으므로 버리기로 결심했다.

저런 놈들에게 10원이라도 내어주는건 용납할 수도 없기 때문이다.

(참고로 중요한 데이타라고 하더라도 비용 지불한 후에 돌려받는다는 보장은 없다.)

 

원인은 매우 간단하다. (그렇기에 더 어이가 없었던 것)

계정 인증이 되어있지 않았기 때문인데 mysql 이나 다른 DB는 설치시 기본적으로 계정 설정에 대한 정보를 물었던 것으로 기억한다.

 

몽고DB의 경우 설치시 디폴트로 계정 설정이 되지 않고 계정 없이 몽고DB에 어드민 권한으로 접근할 수 있게 된다.

여기에 네트웍 망이 public이라면 '내 데이타를 가져가주세요' 광고하는 꼴이다.

 

사실 그동안은 네트워크가 내부망으로 구성이 되어있기 때문에 외부에서 DB를 접속할 수 없었고,

계정 설정이 안되어 있어도 크게 문제는 없었을 것이다.

 

나는 외부 미팅으로 로컬 DB를 잠깐 접근할 필요가 있어서 공유기 포트포워딩 세팅으로 외부망 접근을 열어놓았다.

이 때 몽고DB 내부 접근 계정이라도 만들어 놓았어야 했는데 그걸 하지 않았기에 이 사단이 난 듯 하다.

 

보안은 아무리 로컬에 구성한다해도 이처럼 어떤 경우가 발생할지 모르므로 계정 인증 설정은 항시 해놓는 것이 문제를 일으키지 않을 것 같다. 설정할 때 비밀번호를 허술하게 해놓는다면 설정하지 않는 것과 비슷할 수 있다.

 

브루트 포스 공격(Brute force attack)이라는 흔한 암호 해독 공격 방식이 있는데 이는 문자열의 경우의 수를 다 대입하여 적용해보는 것이다. 그러니 비밀번호가 너무 단순하다면 인증 설정이 되어있어도 해킹에 노출될 수 있다. 꼭 복잡한 암호를 설정하길 바란다.

 

아마 해커들은 현재도 전세계 피씨를 가리지 않고 아이피를 스캔하여 계정 인증 없이 노출된 서버들을 찾아다니고 있을 것이다. 궁금하다면 몽고DB에 그럴싸한 데이타를 올려놓고 계정 인증 없이 외부망으로 노출시키면 3일 이내에 나와 같은 현상을 발견할 수 있을 것 같다.

 

여러분도 항상 보안에 신경써서 이런 자질구레한 일들이 벌어지지 않길 바란다.

 

반응형

+ Recent posts