IT/[ Bigdata ]

[ Bigdata ] 04. MongoDB

kim.svadoz 2020. 8. 10. 13:35
반응형

20-03-16 월

MongoDB

  • NoSQL?

  • 비정형데이터

  • 스키마가 아니다 ( 이 컬럼은 무슨 타입이고 저건 무슨 타입이고 .. )

  • JSON으로 처리한다.

  • 문서를 기반으로 하기 때문에 조인을 할 수 없다.(하나의 문서 안에 모든 데이터가 들어가있음)

  • 레드햇계열의 리눅스? 데드뭐뭐계열의 리눅스?

image-20200316094051032

  • C:\Program Files\MongoDB\Server\3.6\bin 를 windows path 등록

image-20200316100749570
image-20200316100937095
image-20200316101203991

  • 데이터가 저장될 폴더가 필요하다! iot에 bigdata에 mongodata라고 만들자~

image-20200316101757913

  • MongoDB Enter Prise로 서버 접속하기

image-20200316102057052
image-20200316102117540

  • 실행됐구나~ 확인~

image-20200316102440076

  • 웹에서 포트 접속해보기

image-20200316102819916

  • 데이터베이스를 만들고 그 안에서 작업하는 개념! ( ex. conn scott/tiger )

image-20200316103903971
image-20200316104142170

​ => mydb에 아직 아무것도 안만들어 놨기 때문에 아무 것도 안 뜬다~

1. 용어

  • RDBMS : MongoDB
    • table : collection
    • column(컬럼) : field
    • row(레코드) : document
    • 기본키 : _id

2. 명령어

image-20200316104719054

=>

1. collection(RDBMS에서의 테이블)

관계형 데이트에이스 처럼 스키마를 정의하지 않는다.

  • 종류

    • capped collection

      => 고정사이즈를 주고 생성하는 컬렉션

      => 미리 지정한 저장공간이 모두 사용이 되면 맨 처음에 저장된 데이터가 삭제되고 공간으로 활용

    • non capped collection

      => 일반적인 컬렉션

  • 생성 명령문

    db.createCollection("컬렉션명")
        => 일반 collection
    db.createCollection("컬렉션명",{옵션 list})
        => 각각의 옵션을 설정해서 작업(JSON)

    image-20200316111601657

  • 컬렉션이 capped속성인지 아닌지 확인하기

    db.컬렉션명.isCapped()

    image-20200316112046357

  • 컬렉션의 속성 확인하기 => JSON으로 뿌려준다

    db.collection명.valiedate()
  • 삭제 명령문

    db.collections명.drop()

image-20200316112208484

  • 컬렉션명 변경 명령문

    db.컬렉션명.renameColletion("변경할 컬렉션명");

image-20200316113853049

​ << 실습 >>

mini 데이터베이스 생성

emp (size : 10000, capped컬렉션)

shop (일반 컬렉션)

데이터베이스 목록, 컬렉션 목록, 컬렉션 validate() 화면 캡쳐

3. MongoDB에 insert하기

document(관계형db에서의 레코드 개념)에 대한 정보는 JSON의 형식으로 생성

mongodb에서 document를 삽입하면 자동으로 _id가 생성

[구문]
db.컬렉션명.insert({데이터...})
db.컬렉션명.insertOne({데이터...})
db.컬렉션명.inserMany({데이터...})
  • "_id" : ObjectID("5e6ee7751bf5731af5cb2f8");

    < 현재 timestap + machine id + mongodb프로세스id + 순차번호(추가될 때마다 증가) >

image-20200316114604831

​ => 스키마가 없기 때문에, 비정형 데이터를 넣기 적합하다~

  • 변수에다 저장해놓고 값을 넣어도 된다.

image-20200316131429973

  • 특정 값을 for문으로 설정 가능

image-20200316131910078

  • 배열은 [ ] 로 처리

image-20200316132344200
image-20200316132412257

  • 배열로 한꺼번에 처리할 수도 있다~

image-20200316132750098

​ => 추가로 it을 누르면 더 볼 수 있어용~

4. MongoDB에 update하기

document 수정

조건을 적용해서 수정하기 위한 코드도 JSON으로 구현

[업데이트를 위한 명령어]
  • $set : 해당필드의 값을 변경(업데이트를 하기 위한 명령어)
    • non capped collection인 경우 업데이트할 필드가 없는 경우 추가한다.
  • $inc : 해당필드에 저장된 숫자의 값을 증가
  • $unset : 원하는 필드를 삭제할 수 있다.
  • 업데이트 옵션
    • multi : true를 추가하지 않으면 조건에 만족하는 document 중 첫 번재 document만 update 된다.
[구문]
db.컬렉션명.update({조건필드:값}), // sql의 update문의 where절
                {$set:{수정할필드:수정값}},
                {update와 관련된 옵션:옵션값})

image-20200317094957787

​ << 실습 >>

  1. id가 kang사람의 dept를 "총무"로 변경
  2. dept가 "전산'인 모든 addr을 "안양"으로 변경
  3. id가 jang인 document의 bonus를 1000추가하기
  4. dept가 "인사"인 모든 document의 bonus에 2000을 추가하기

작업완료 후 캡쳐해서 메일 전송

5. MongoDB에서 배열 관리

db.score.update({id:"jang"}, 
    {$set:
        {info:
            {city:["서울","안양"],
            movie:["겨울왕국2","극한직업","쉬리"]
            }
        }
    }
)
[배열에서 사용할 수 있는 명령어]
  • addToSet : 배열의 요소를 추가 ( 중복 체크 )

    db.score.update({id:"jang"}, {$addToSet:{"info.city":"인천"}});
        // 중복된 데이터는 들어가지 않는다.
  • push : 배열의 요소를 추가 ( 중복 허용 )

    db.score.update({id:"jang"}, {$push:{"info.city":"천안"}});
        // 중복된 데이터도 추가로 puash된다.
  • pop : 배열에서 요소를 제거할 때 사용

    => 1이면 마지막 요소를 제거, -1이면 첫 번째 요소를 제거

    db.score.update({id:"jang"}, {$pop:{"info.city":1}}); // 오른쪽 끝에서 한 개 삭제
    db.score.update({id:"jang"}, {$pop:{"info.city":-1}}); // 왼쪽 끝에서 한 개 삭제
  • each : addToSet이나 push에서 사용할 수 있다.

    db.score.update({id:"jang"},
                    {$push:
                        {"info.city":
                            {$each:["천안","가평","군산"]}
                        }
                    });
  • sort : 정렬( 1: 오름차순, -1 : 내림차순)

    db.score.update({id:"jang"},
                    {$push:
                        {"info.city":
                            {$each:["천안","가평","군산"], $sort:1}
                        }
                    });
  • pull : 배열에서 조건에 만족하는 요소를 제거(조건 한 개)

    • pullAll : 조건 여러개
    db.score.update({id:"jang"},
                    {$pull:{"info.city":"천안"}    
                    }
                    );
    
    db.score.update({id:"jang"},
                    {$pullAll:{"info.city":["가평","군산"]}    
                    }
                    );                

​ << 실습1 >>

score collection을 이용해서 작업해보세요

1. song,jang,hong에 다음과 같은 값을 가질 수 있도록 배열로 필드를 추가하세요

song : history (영업1팀, 총무, 기획실)

jang: history(전략팀,총무,전산)

hong : history(영업1팀, 기획실,전산)

2. song의 document history에 자금부를 추가하세요

3. jang의 document의 history에 마지막 데이터를 제거하세요

4. servlet데이터가 100점인 모든 document에 bonus를 3000을 추가하세요. 기존데이터가 존재하면 증가되도록 구현하세요

5. song의 lang.ms에 "visual basic","asp",".net"을 한꺼번에 추가하세요

  1. db.score.update({id:"song"}, {$set:{history:["영업1팀", "총무", "기획실"]}});
    db.score.update({id:"jang"}, {$set:{history:["전략팀", "총무", "전산"]}});
    db.score.update({id:"hong"}, {$set:{history:["영업1팀", "기획실", "전산"]}});

  2. db.score.update({id:"song"}, {$addToSet:{history:"자금부"}});
    db.score.update({id:"song"}, {$pop:{history:1}});

  3. db.score.update({id:"jang"}, {$pop:{history:1}});

  4. db.score.update({servlet:100}, {$inc:{bonus:3000}}, {multi:true});

  5. db.score.update({id:"song"}, {$push:{"lang.ms":{$each:["visual basic","asp",".net"]}}});

​ << 실습 2 >>

다음과 같은 조건으로 document를 구성해 보도록 하겠습니다.

게시물과 댓글을 mongodb에 저장

\1. board 컬렉션을 생성

\2. document는 5개 insert

no,id,title,content,count,writedate

\3. 2번째 게시물에는 댓글이 3개 추가되도록

update - 하위object와 배열로 구성

댓글의 필드

content,count1,count2,writedate

db.createCollection("board");
db.board.insert({insertno:1, title:"aaaaaaaa", content:"hello1", count:11, wirtedate:"2020-03-16", id:"kim"});
db.board.insert({insertno:1, title:"bbbbbb", content:"hello2", count:22, wirtedate:"2020-03-17", id:"park"});
db.board.insert({insertno:1, title:"ccccccc", content:"hello3", count:33, wirtedate:"2020-03-18", id:"jung"});
db.board.insert({insertno:1, title:"ddddddd", content:"hello4", count:44, wirtedate:"2020-03-16", id:"choi"});
db.board.insert({insertno:1, title:"eeeeeee", content:"hello5", count:55, wirtedate:"2020-03-16", id:"lee"});

comment1={content:"hi", count1:0, count2:0, writedate:"2020-04-01"};
comment2={content:"HELLO", count1:0, count2:0, writedate:"2020-04-02"};
comment3={content:"bye", count1:0, count2:0, writedate:"2020-04-03"};

db.board.update({content:"hello2"}, {$push:{"sub":comment1}});
db.board.update({content:"hello2"}, {$push:{"sub":comment2}});
db.board.update({content:"hello2"}, {$push:{"sub":comment3}});

20-03-17 화

  • MongoDB도 클러스터링으로 한대처럼 사용할 수 있다.
  • 하지만 하둡의 hdfs와 맵리듀스를 성능적으로 훨씬 효율적이지만, MongoDB를 쓰는 경우도 있다~
  1. Aggregation
  2. map-reduce
  • 몽고디비는 많은양의 데이터를 가지고 해야 하거나, 복잡한 타입의 테이블이 필요할 때 사용하는거~

6. advanced MongDB

  • 이쁘게 출력하기

    db.컬렉션명.find().pretty()
  • 변수처럼 사용할 수 있다.

image-20200317095429357

  • 전체 데이터의 갯수를 리턴

    db.컬렉션명.find().count()

image-20200317163431643

​ << 실습 1 >>

​ score의 모든 document에 num필드(1000)가 추가되도록 작업하고 실행결과 보기

var x = db.score.find();
while(x.hasNext()){
           var one = x.next();
           one.num = 1000;
           db.score.save(one);
                   }
db.score.find();         
[명령어]
  • find

    db.컬렉션명.find(조건, 조회할 필드에 대한 명시)
    • db.컬렉션명.find({})와 동일

      => { }안에 아무것도 없으면 전체 데이터 조회

    • 조건, 조회할 필드에 대한 명시 모두 JSON

    • 조회할 필드의 정보를 정보 명시

      => 형식 : {필드명:1...} : 화면에 표시하고 싶은 필드

      ​ {필드명:0} : 명시한 필드가 조회되지 않도록 처리

    • [ 조건 ]

      • $lt : <
      • $gt : >
      • $lte : <=
      • $gte : >=
      • $or : 여러 필드를 이용해서 같이 비교 가능
      • $and : and연산
      • $in : 하나의 필드에서만 비교
      • $nin : $in으로 정의한 조건을 제외한 document를 조회 ( not in )
ex) addr이 인천인 데이터 : id, name, dept, addr 출력

```bash
db.score.find({addr:"인천"},{id:1,name:1,dept:1,addr:1})
db.score.find({addr:"인천"},{id:1,name:1,dept:1,addr:1,_id:0}) // 기본키(_id) 제거

ex) score컬렉션에서 java가 90점인 이상인 document 조회 : id, name, dept, java만 출력

db.score.find({java:{$gte:90}},{id:1,name:1,dept:1,java:1,_id:0})

ex) dept가 인사이거나 addr이 인천인 데이터 조회

db.score.find({$or:[{dept:"인사"},{addr:"인천"}]})

ex) id가 song, kang, hong인 데이터 조회

db.score.find({$or:[{id:"song"},{id:"hong"},{id:"kang"}]})
db.score.find({id:{$in:["song","kang","hong"]}})

ex) id가 song, kang, hong이 아닌 데이터 조회

db.score.find({id:{$nin:["song","kang","hong"]}})

-   조회메소드

    -   findOne() : 첫번째 document 만 리턴

    -   find() : 모든 document리턴

    -   count() : 행의 갯수를 리턴

    -   sort({필드명:sort옵션}) : 정렬

        ​ 1 : 오름차순

        ​ -1 : 내림차순

    -   limit(숫자) : 숫자만큼의 document만 출력

    -   skip(숫자) : 숫자만큼의 document를 skip하고 출력하고 조회

ex) 여러가지 조회

db.score.find({num:null})
db.score.find().sort({id:1});
db.score.find().sort({java:-1});
db.score.find().limit(5)
db.score.find().skip(5)

-   정규표현식을 적용

    ```
    db.컬렉션명.find({조건필드명:/정규표현식/옵션})
    ```

    -   **\[ 기호 \]**

        -   | : or

        -   ^ : ^ 뒤의 문자로 시작하는지 체크

        -   \[ \] : 영문자 하나는 한 글자를 의미하고 \[ \]로 묶으면 여러 글자를 표현

            \[ a-i \] : a에서 i까지 모든 영문자

    -   **\[ 옵션 \]**

        -   i : 대소문자 구분없이 조회 가능

ex) id가 kim과 park인 document 조회

db.score.find({id:/kim|park/})
db.score.find({id:/kim|park/i}) // 대소문자 구분없이

ex) id가 k로 시작하는 document 조회

db.score.find({id:/^k/})
db.score.find({id:/^k/i}) //대소문자 구분없이

ex) id에 [a-i]까지 영문이 있는 id를 조회

db.score.find({id:/[a-i]/})

ex) id가 k-p로 시작하는 document 조회

db.score.find({id:/^[k-p]/})

ex) id에 a랑 i가 있는 document 조회

db.score.find({id:/[ai]/})

#### 7\. MongoDB에 저장된 데이터 삭제하기 - remove()

> 조건을 정의하는 방법은 find()나 update()와 동일

-   삭제해보아용~

    ex) servlet 점수가 80점 이하인 document 삭제

    ```
    db.score.remove({servlet:{$lt:80}})
    ```


-   투표 : 30%

-   코드내용 : 50%

    -   기능이 얼마나 많이 구현되었는지
    -   수업시간에 배운 내용이 충실하게 구현되었는지
    -   open api를 사용해서 새로운 기능에 도전했는지
    -   실무에서 사용할 수 있는 형태를 고민해서 구현했는지
    -   발표할 때 에러 없이 잘 실행
    -   계획한 내용을 잘 완료
-   협업 : 20%

    ​

    ​ << 실습 2 >>

    **1\. Score collection에서 이름과 주소와 servlet점수를 출력해보자**

    db.score.find({},{name:1,addr:1,servlet:1,\_id:0})

    **2\. Score collection에서 java점수 중 70점 이상을 출력해보자**

    db.score.find({java:{$gte:70}});

    **3\. Score collection에서 이름, java점수를 출력하고 bonus가 2000이상**

    **인 사람만 출력해보자**

    db.score.find({bonus:{$gte:2000}}, {name:1, java:1, \_id:0})

    **4\. score에서 dept가 인사이면서 addr이 안양이거나 대구인 document 출력**

    db.score.find({$and:\[{dept:"인사"}, {addr:{$in:\["안양","대구"\]}}\]})

    **5\. servlet이 70에서 90사이이며 dept가 총무인 document 조회**

    db.score.find({$and:\[{dept:"총무"}, {$and:\[{servlet:{$gte:70}}, {servlet:{$lt:90}}\]}\]})

    **6\. score에서 이름에 김씨인 사람 조회해보기**

    db.score.find({name:/^\[김\]/})

    **7\. score에서 servlet점수가 가장 낮은 document와 가장 높은 document 출력하기**

    db.score.find({servlet:{$not:{$exists:null}}}).sort({servlet:1}).limit(1);

    db.score.find().sort({servlet:1}).limit(1)  
    db.score.find().count() // 13  
    db.score.find().sort({servlet:1}).skip(12)

    **8\. java점수가 가장 높은 document중에 7개를 출력하되 2개를 건너뛰고 출력해보자**

    db.score.find().sort({java:-1}).skip(2).limit(7)

    **9\. 아이디에 n과 o가 들어가는 document 구하기**

    db.score.find({id:/\[no\]/i})


#### 8\. Aggregation

-   Oracle에서의 Group by와 동일 개념

-   간단한 집계를 구하는 경우 mapreduce를 적용하는 것 보다 간단하게 작업 가능

-   Pipeline을 내부에서 구현

    \=> 한 연산의 결과가 또 다른 연산의 input데이터로 활용

    \=> [https://docs.mongodb.com/v3.6/aggregation/의](https://docs.mongodb.com/v3.6/aggregation/%EC%9D%98) pipeline 참고


##### \[ 명령어 \]

-   $match : where절, having절
-   $group : group by
-   $sort : order by
-   $avg : avg그룹함수
-   $sum : sum그룹함수
-   $max : max그룹함수

##### \[ 형식 \]

db.컬렉션명.aggregate(aggregate 명령어를 정의)
----------------------- => 여러가지를 적용해야 하는 경우 배열로 표현

$group:{_id:그룹으로 표시할 필드명,
연산결과를 저장할 필드명:{연산함수:값}}
---- => 숫자나 필드 참조
$match:{필드명:{연산자:조건값}}
--------------- => 비교연산 or 조건이 여러 개


-   addr별 인원수

    ```
    db.exam.aggregate([{$group:{_id:"$addr", num:{$sum:1}}}]);
    ```

-   dept별 인원수

    ```
    db.exam.aggregate([{$group:{_id:"$dept", num:{$sum:1}}}]);
    ```

-   dept별 java점수의 평균

    ```
    db.exam.aggregate([{$group:{_id:"$dept", num:{$avg:"$java"}}}])
    ```

-   addr별 servlet합계

    ```
    db.exam.aggregate([{$group:{_id:"$addr", num:{$avg:"$servlet"}}}])
    ```

-   dept별 java점수의 평균. 단, addr이 인천인 데이터만 작업 $match를 추가

    ```
    db.exam.aggregate([{$match:{addr:"인천"}}, {$group:{_id:"$dept", num:{$avg:"$java"}}}])
    ```


​ << 실습 3 >>

**1\. dept가 인사인 document의 servlet평균 구하기**

db.exam.aggregate([{$match:{dept:"인사"}}, {$group:{_id:"$dept", num:{$avg:"$servlet"}}}])


**2\. java가 80점이 넘는 사람들의 부서별로 몇 명인지 구하기**

db.exam.aggregate([{$match:{java:{$gte:80}}}, {$group:{_id:"$dept", num:{$sum:1}}}])


**3\. 2번 결과를 인원수데이터를 내림차순으로 정렬해 보세요.**

db.exam.aggregate([{$match:{java:{$gte:80}}}, {$group:{_id:"$dept", num:{$sum:1}}},{$sort:{num:-1}}])


#### 9\. STS을 이용해서 WEB으로 MongoDB 데이터 확인하기 위한 설정

![image-20200317163537044](https://user-images.githubusercontent.com/58545240/89754057-52e8b500-db15-11ea-98df-4b9a5af78b3a.png)
![image-20200317163557473](https://user-images.githubusercontent.com/58545240/89754061-554b0f00-db15-11ea-8e96-9892b44b94f4.png)
![image-20200317171204262](https://user-images.githubusercontent.com/58545240/89754063-567c3c00-db15-11ea-880b-30edfd20bca4.png)

src - main - webapp - WEB-INF - spring - appServlet - servlet-context.xml 에서

<context:component-scan base-package="spring.data.mongodb" />

```

image-20200317171236685

image-20200318092851061


20-03-16 수

  • 몽고디비는 중간저장소?! 단기간 요청이 몰릴 수 있는 로그들을 작업하는?! 스키마 때문에?!
  • 스키마가 없기 때문에 유연성이 있다!
  • 성능면에서 update(오버헤드 발생 가능)보다 insert가 낫다!
  • 요즘 시스템들이 JSON포맷이 많이 발생 하기 때문에 이것또한 몽고디비의 매력을 상승

10. MongoDB를 이용해 File Export/Import 해보기

  • test.csv 를 C:iot 폴더에 복사 후 새 cmd창을 이용해 파일 export해보기

image-20200318093017105

image-20200318093105969

image-20200318093950544

  • test.csv를 C:\iot폴더에 복사 후 iot에 있는 파일 import해보기

image-20200318094240835

image-20200316102057052

​ -d : database

​ -c : collection

  • 지금은 local이라 그냥 써주면 되지만 아니라면, /host 와 /port 설정해줘야 한다!

11. MongoDB로 Client 프로그램 만들기

STS-mongoTest에서 확인 !

반응형