Skip to main content

[dB's 몽고DB] MongoDB 데이터베이스 사용하기

오라클, MySQL 을 관계형 데이터베이스 라고 합니다. 이는 데이터를 담고 있는 복수 개의 테이블들이 긴밀하게 연결되어 있기 때문입니다. 이와 다르게, 몽고DB는 NoSQL 입니다. "SQL이 필요없다"가 아니라 "비관계형 데이터베이스 SQL" 이라는 뜻을 내포하고 있습니다. 이유는, DB에 접근하기 위해서는 결국 몽고DB에서 사용하는 쿼리문법이 필요하기 때문입니다.

특별히, 몽고DB는 자바스크립트 객체를 그대로 저장할 수 있어서 자바스크립트를 사용하는 노드에서 데이터를 저장하기에 적합합니다. 그렇기 때문에 데이터 저장, 조회 방식도 기존 SQL과 다릅니다. 이는 성능을 최우선으로 생각하기 때문에 고안된 방법이며 실시간 서비스나 대용량 트래픽을 감당할 수 있는 메시징 시스템등에 사용됩니다.

몽고DB는 데이터베이스의 테이블 대신, 여러 데이터가 모인 컬렉션(Collection)을 사용합니다. 즉, 데이터베이스는 컬렉션의 집합이고 각각의 컬렉션은 여러개의 문서객체(Document)를 가질 수 있습니다.

1. 몽고DB 설치하기

  • 몽고DB 다운로드 센터로 이동
  • Installing with Homebrew
  • 몽고DB 설치 brew install mongodb
  • 데이터베이스 저장 폴더 만들기 mkdir -p /data/db
  • 권한 부여하기 chown $USER /data/db
  • 몽고DB 활성화가 되면서 27017 포트에서 연결을 기다린다는 메시지가 표시됨  mongod
  • 몽고Shell 접속하기 새로운 터미널에서 mongo

2. 데이터베이스 생성과 입력, 삭제

  • 데이터베이스 지정 use local
  • 컬렉션 만들기 db.users.insert({name: '소녀시대'})
  • 컬렉션 문서조회 db.users.find().pretty()
  • 문서삭제 db.users.remove({name:/소녀시대/})
  • 로그인에 필요한 데이터 입력 db.users.insert({id: 'test01', name: '소녀시대', passworld: '1234'})

3. 몽고DB 연결 및 사용하기

먼저 몽고DB를 사용할 수 있도록 mongodb 모듈을 불러옵니다. 바로, MongoClient 속성을 참조합니다. connectDB함수는 mongodb 모듈을 사용해 몽고디비 데이터베이스에 연결하도록 새로 만든 것입니다. 연결정보는 문자열로 정의해야 합니다. (IP정보, 포트정보, 데이터베이스이름) 데이터 베이스 연결을 위해서 connect() 메소드를 호출합니다. 데이터베이스가 정상적으로 연결이 되면 db 객체가 전달되며 이를 database 변수에 저장합니다. 서버가 실행되면 connectDB 함수를 호출합니다.

var MongoClient = require('mongodb').MongoClient;

var database;

function connectDB() {
 var databaseUrl = 'mongodb://localhost:27017/local';

 MongoClient.connect(databaseUrl, function(err, db) {
  if (err) throw err;

  database = db;
 });
 }

4. 사용자 아이디와 비밀번호 비교 (/login.html)

authUser() 함수는 데이터베이스 객체, 아이디, 비밀번호, 콜백함수를 파라미터로 받습니다. database.collection() 메소드로 users 컬렉션 객체를 참조합니다. find() 메소드를 호출하여 데이터를 조회합니다. id, password를 파라미터로 전달하며 조회 결과는 toArray() 메소드를 사용해 배열로 변환합니다. 메소드의 파라미터로 전달된 콜백함수에는 toArray()로 변환된 문서 객체가 전달 됩니다. 이 과정을 간단히 정리하면 connect() -> collection() -> find() 단계로 몽고DB에서 문서 객체를 찾습니다.

var authUser = function(database, id, password, callback) {
 console.log('authUser 호출됨 : ' + id + ', ' + password);
 
    // users 컬렉션 참조
 var users = database.collection('users');

    // 아이디와 비밀번호를 이용해 검색
 users.find({"id":id, "password":password}).toArray(function(err, docs) {
  if (err) { // 에러 발생 시 콜백 함수를 호출하면서 에러 객체 전달
   callback(err, null);
   return;
  }
  
     if (docs.length > 0) {  // 조회한 레코드가 있는 경우 콜백 함수를 호출하면서 조회 결과 전달
      console.log('아이디 [%s], 패스워드 [%s] 가 일치하는 사용자 찾음.', id, password);
      callback(null, docs);
     } else {  // 조회한 레코드가 없는 경우 콜백 함수를 호출하면서 null, null 전달
      console.log("일치하는 사용자를 찾지 못함.");
      callback(null, null);
     }
 });
}

5. 사용자 추가 기능 만들기 (/adduser.html)

addUser() 함수에 데이터베이스, id, password, name 파라미터 값을 전달합니다. insertMany() 메소드를 호출하여 데이터를 추가합니다. 넘어오는 결과 객체 안에 있는 insertedCount 속성으로 추가된 레코드의 개수를 알려줍니다.

var addUser = function(database, id, password, name, callback) {
 console.log('addUser 호출됨 : ' + id + ', ' + password + ', ' + name);
 
 // users 컬렉션 참조
 var users = database.collection('users');

 // id, password, username을 이용해 사용자 추가
 users.insertMany([{"id":id, "password":password, "name":name}], function(err, result) {
  if (err) {  // 에러 발생 시 콜백 함수를 호출하면서 에러 객체 전달
   callback(err, null);
   return;
  }
  
        // 에러 아닌 경우, 콜백 함수를 호출하면서 결과 객체 전달
        if (result.insertedCount > 0) {
         console.log("사용자 레코드 추가됨 : " + result.insertedCount);
        } else {
            console.log("추가된 레코드가 없음.");
        }
        
     callback(null, result);
      
 });
}

6. CRUD에 필요한 메소드

자주 사용되는 메소드에 대해 알아보도록 하겠습니다. 데이터베이스에 접근한 뒤 각 컬렉션에 있는 문서를 조회/추가/업데이트/삭제 할 때 collection 에서 제공하는 method가 필요합니다. (메소드 메뉴얼) 대표적으로 find(), findOne(), insert(), findOneAndUpdate(), deleteOne() 등이 있습니다.

7. 몽구스 데이터베이스 다루기

몽구수(mongoose)는 데이터입력시 일정한 틀인 스키마(Schema)를 만들고 문서 객체를 저장할 수 있게 해줍니다. 자바스크립트 객체와 데이터베이스 객체를 서로 매칭하여 바꿀 수 있게 하는 것을 오브젝터 맵퍼(Object Mapper)라고 하며, 이 중에서 가장 많이 사용하는 것이 바로 몽구스 모듈입니다.

mongoose 모듈 대표 메소드
  • connect(): mongoose를 사용해 데이터베이스에 연결합니다. 연결 후에는 mongoose.connection 객체를 사용해 연결관련 이벤트를 처리할 수 있습니다.
  • Shcema(): 스키마를 정의하는 생성자입니다.
  • model(): 모델을 정의합니다.
mongoose 모듈로 데이터베이스에 연결하며 연결정보는 mongodb 모듈과 같습니다. connect() 메소드를 호출하면서 동시에 데이터베이스 연결 정보를 파라미터로 넘겨줍니다. 데이터베이스에 연결되면 스키마를 정의합니다. 스키마에 들어가는 각 속성은 스키마타입(Schema Type)을 가집니다. 
  • String, Number, Boolean, Array, Buffer, Date, ObjectId, Mixed
스키마는 단순히 구조만 정의하므로 데이터베이스에 들어 있는 컬렉션을 지정 하려면 모델을 만들어야 합니다. model() 메소드를 사용하면 데이터베이스의 컬렉션을 지정하는 모델 객체를 만들 수 있습니다.

function connectDB() {
 // 데이터베이스 연결 정보
 var databaseUrl = 'mongodb://localhost:27017/local';
  
 // 데이터베이스 연결
    console.log('데이터베이스 연결을 시도합니다.');
    mongoose.Promise = global.Promise;  // mongoose의 Promise 객체는 global의 Promise 객체 사용하도록 함
 mongoose.connect(databaseUrl);
 database = mongoose.connection;
 
 database.on('error', console.error.bind(console, 'mongoose connection error.')); 
 database.on('open', function () {
  console.log('데이터베이스에 연결되었습니다. : ' + databaseUrl);
  

  // 스키마 정의
  UserSchema = mongoose.Schema({
   id: String,
   name: String,
   password: String
  });
  console.log('UserSchema 정의함.');
  
  // UserModel 모델 정의
  UserModel = mongoose.model("users", UserSchema);
  console.log('UserModel 정의함.');
  
 });
    
    // 연결 끊어졌을 때 5초 후 재연결
 database.on('disconnected', function() {
        console.log('연결이 끊어졌습니다. 5초 후 재연결합니다.');
        setInterval(connectDB, 5000);
    });
}
model() 메소드의 첫 번째 파라미터로는 모델 이름이 전달되고 두 번째 파라미터에는 스키마 객체가 전달됩니다. UserModel 변수에 할당합니다. 데이터베이스 컬렉션에 들어 있는 문서를 조회, 수정, 삭제하기 위해 find(), save(), update(), remove() 메소드를 사용할 수 있습니다.

8. 몽구스 - 사용자 인증


var authUser = function(database, id, password, callback) {
 console.log('authUser 호출됨 : ' + id + ', ' + password);
 
    // 아이디와 비밀번호를 이용해 검색
 UserModel.find({"id":id, "password":password}, function(err, results) {
  if (err) {  // 에러 발생 시 콜백 함수를 호출하면서 에러 객체 전달
   callback(err, null);
   return;
  }
  
  console.log('아이디 [%s], 패스워드 [%s]로 사용자 검색결과', id, password);
  console.dir(results);
  
     if (results.length > 0) {  // 조회한 레코드가 있는 경우 콜백 함수를 호출하면서 조회 결과 전달
      console.log('아이디 [%s], 패스워드 [%s] 가 일치하는 사용자 찾음.', id, password);
      callback(null, results);
     } else {  // 조회한 레코드가 없는 경우 콜백 함수를 호출하면서 null, null 전달
      console.log("일치하는 사용자를 찾지 못함.");
      callback(null, null);
     }
 });
};

9. 몽구스 - 사용자 등록


var addUser = function(database, id, password, name, callback) {
 console.log('addUser 호출됨 : ' + id + ', ' + password + ', ' + name);
 
 // UserModel 인스턴스 생성
 var user = new UserModel({"id":id, "password":password, "name":name});

 // save()로 저장 : 저장 성공 시 addedUser 객체가 파라미터로 전달됨
 user.save(function(err, addedUser) {
  if (err) {
   callback(err, null);
   return;
  }
  
     console.log("사용자 데이터 추가함.");
     callback(null, addedUser);
      
 });
};


참고자료
https://medium.com/of-all-things-tech-progress/5-steps-to-build-a-rest-api-in-node-js-with-mongodb-e1f2113a39bd

Comments

Popular posts from this blog

[dB's 리액트] Render Prop 사용하기

HOC는 코드 재사용 문제를 해결하기 위해 고안되었습니다. createClass 패러다임에서는 이러한 문제를 mixins으로 해결하였습니다. ES6 classes 가 등장하고 createClass는 사라지기 시작했습니다. 하지만 ES6 클래스는 mixins을 지원하지 않는다는 문제점이 있었습니다. 그 결과 HOC가 등장하였으며 재사용에 대한 이슈를 해결한 듯 보였지만, 기존 mixins이 가지고 있던 모든 이슈들을 해결한 건 아니였습니다. Render Props를 사용하면 mixins과 HOC가 가지고 있는 문제점들을 해결할 수 있습니다. Render Props 패턴은 함수로 이루어진 props를 이용하여  컴포넌트 간 코드를 공유하는 방법입니다. <DataProvider render={data => ( <h1>Hello {data.target}</h1> )}/> import React from 'react' import ReactDOM from 'react-dom' import PropTypes from 'prop-types' // Instead of using a HOC, we can share code using a // regular component with a render prop! class Mouse extends React.Component { static propTypes = { render: PropTypes.func.isRequired } state = { x: 0, y: 0 } handleMouseMove = (event) => { this.setState({ x: event.clientX, y: event.clientY }) } render() { return ( <div style={{ height: '100%' }} on...

[dB's 리액트] 리액트 16.3 무엇이 바뀌었나?!

리액트 16.3 버전이 새롭게 업데이트 되었습니다. 새로운 라이프 사이클과 API들이 소개 되었습니다: context API, ref forwarding API, ergonomic ref API 입니다. Context API Context API는 기존에도 제공되었습니다. 하지만, 상속 문제로 인해 사용 빈도가 적었으며 더 좋은 방법들로 대체되었습니다. 예로, redux, react-router, styled-components 등이 Context API를 기반으로 제작 되었습니다. Context는 CreateContext 함수를 이용해서 제작합니다. 이 함수는 Provider와 Consumer를 호출할 수 있습니다. Provider는 Context에서 사용할 값을 설정하고 Consumer는 설정한 값을 불러올 때 사용합니다. const ThemeContext = React.createContext('light'); class ThemeProvider extends React.Component { state = {theme: 'light'}; render() { return ( <ThemeContext.Provider value={this.state.theme}> {this.props.children} </ThemeContext.Provider> ); } } class ThemedButton extends React.Component { render() { return ( <ThemeContext.Consumer> {theme => <Button theme={theme} />} </ThemeContext.Consumer> ); } } 링크 https://hackernoon.com/how-to-use-the-new-react-co...