본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


Node.js

Node.js 몽고DB 연동(Nodejs mongodb, Node.js mongodb)을 커넥션(Connection) 클래스에서

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2020. 12. 22.

Node.js에서 몽고db를 연동하려면 대표적으로 사용하는 라이브러리는 몽구스(mongoose) 입니다.

일반적인 몽구스(mongoose) 사용법은 스키마(Schema)와 모델(model)을 생성하여 사용하는 것 입니다.

일반적인 사용 예제는 아래와 같습니다.

var mongoose = require("mongoose");
var Schema = mongoose.Schema;

var url = 'mongodb://접속주소:27017/admin';
mongoose.connect(url, { useNewUrlParser: true }); 

//#1. 스키마를 정의 합니다.
var structor = new Schema({  
    "date":Date,
    "text" : string,
    "num" : number
});

//#2. 모델을 정의 합니다.
structor.set('collection', '컬렉션');
var target = mongoose.model("컬렉션", structor );

//#3. 데이터를 조회 합니다.
const docs = await target.find({ });
docs.map(doc => doc.name).sort(); //결과 값

 

 

스키마(Schema)를 생성 한 뒤에 모델(model)객체를 만들고, 모델을 가지고 등록, 수정, 삭제를 하면 되는 코드 입니다.

위 코드는 사실 사용하는 데 문제는 없습니다만, 컬렉션(collection)별로 스키마를 만들어주고 모델을 생성 해야 합니다.

소위 말하는 vo객체(Value Object)를 만들어 주어야 하는 부분이 항상 존재 합니다.

몽고DB(mongodb)의 강력한 기능 중 한가지는 컬렉션의 스키마를 굳이 정의 해 주지 않아도 자유롭게 CRUD 행위를 할수 있는 점 입니다.

위 방식은 데이터가 잘못 들어가거나 불필요한 내용이 저장되는 것을 방지 해 주는 좋은 기능입니다.

사용자는 데이터를 관리하기 전 항상 스키마를 만들고, 모델을 만든 뒤에 데이터베이스를 사용 하여야 합니다.

 

만약 데이터를 구분하는 키(KEY) 값이 자주 변하는 환경에서는 다소 불편 합니다.

매번 변하는 키(Key) 값에 대해서 스키마를 재 정의 해 주어야 하기 때문입니다.

 

 

#. 커넥션(Connection) 클래스(Interface) ─────────────────────

 * 환경

  - 몽고DB : 싱글 인스턴스

  - 타입스크립트 : 4.1.3

  - 몽구스 : 5.11.8

 

 

몽구스(mongoose)에서 커넥션(Connection) 클래스가 존재 합니다.

커넥션(Connection) 클래스(인터페이스)는 몽고DB에 접속한 다음에 사용 할 수 있는 객체 입니다.

컬렉션이라는 클래스(인터페이스)입니다.

 

해당 클래스의 사용법이 직관적이면서 간단하고 콜백(Promise or arrow funciton) 위주로 결과를 확인 할 수 있습니다.

 

테스트를 위해서 2개의 파일을 만들 예정 입니다.

 1. index.ts : 아래 몽고DB 연결 클래스를 사용할 클래스 입니다.

 2. mongoDb.ts : 몽고DB 연결이 존재하는 클래스 입니다.

 

먼저 데이터베이스에 연결하는 코드를 살펴 보겠습니다.

* 파일이름 : mongoDb.ts

import * as mongoose from 'mongoose';

const url = 'mongodb://주소/db이름?minPoolSize=0&maxPoolSize=10';

export class MongDb {
    private static CONS : number;
    private static CONN : mongoose.Connection;

    constructor (){
        if(MongDb.CONS != 1){  //연결이 안된 상태면
            mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }).then( db=>{
                MongDb.CONS = mongoose.connection.readyState || 0;  //1은 접속, 0은 실패
                MongDb.CONN = db.connection;  //사용할 커넥션!!
            })
        }
    }
}    

 

해당 클래스에서의 주요 내용은 몽구스(mongoose)에서 제공되는 connect함수 다음에 사용되는 함수인 then에서의 connection이라는 객체를 가져오는 부분 입니다.

이렇게 만들어진 커넥션(Connection) 객체에는 다양한 함수가 제공 됩니다.

먼저 find 함수를 살펴 보겠습니다.

* 파일이름 : mongoDb.ts

import * as mongoose from 'mongoose';

const url = 'mongodb://주소/db이름?minPoolSize=0&maxPoolSize=10';

export class MongDb {
    private static CONS : number;
    private static CONN : mongoose.Connection;

    constructor (){
        if(MongDb.CONS != 1){  //연결이 안된 상태면
            mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }).then( db=>{
                MongDb.CONS = mongoose.connection.readyState || 0;
                MongDb.CONN = db.connection;  //사용할 커넥션!!
            })
        }
    }
    
    findOne(name : string, query : any, then : any) : void{
        MongDb.CONN.collection(name).findOne(query, then)
    }    
}    

 

findOne이라는 함수를 추가하여 보았습니다.

내용이 매우 직관적입니다. 커넥션(Connection) 객체에서 컬렉션(collection)을 가져 와 findOne 함수를 동작 시켰습니다.

query는 몽고DB에서 사용하는 쿼리와 동일한 구조이며, then은 콜백 형식의 화살표 함수를 넣어주면 됩니다.

* 파일이름 : index.ts

import * as db from './mongoDb'

class MainClass{

    private mongodb;
    
    constructor(){
        mongodb = new db.MongDb();
    }

    runner() {
        mongodb.findOne('컬렉션',{ userId :'admin'}, (fail, succ)=>{

        });
    }
}

const main = new MainClass();
main.runner();

 

findOne 함수에 첫번째 파라미터로 컬렉션이름을 넣었습니다.

두번째 파라미터로 쿼리(질의문, Query)를 넣어 주었습니다.

해당 쿼리는 몽고DB 에서 사용하는 질의문과 100% 동일하게 넣어주면 됩니다.

세번째로 화살표 함수를 넣었습니다. 화살표 함수에서 fail 객체는 오류 발생시 반환되는 객체 입니다.

succ는 오류가 없는 경우 결과값이 존재하는 객체 입니다. 해당 값은 조회된 데이터가 있거나 없을 수 있습니다.

실제로 실행하여 보았습니다.

데이터가 잘 나옵니다~

 

커넥션(Connection) 클래스를 활용하면 이처럼 따로 스키마를 지정하지 않아도 손쉽게 데이터를 관리 할 수 있습니다.

몇가지 예를 좀 더 살펴보겠습니다.

* 파일이름 : mongoDb.ts

import * as mongoose from 'mongoose';

const url = 'mongodb://주소/db이름?minPoolSize=0&maxPoolSize=10';

export class MongDb {
    private static CONS : number;
    private static CONN : mongoose.Connection;

    constructor (){
        if(MongDb.CONS != 1){  //연결이 안된 상태면
            mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }).then( db=>{
                MongDb.CONS = mongoose.connection.readyState || 0;
                MongDb.CONN = db.connection;  //사용할 커넥션!!
            })
        }
    }
    
    findOne(name : string, query : any, then : any) : void{
        MongDb.CONN.collection(name).findOne(query, then)
    }
    
    insert(name : string, data : any, then : any): void{
        MongDb.CONN.collection(name).insertOne(data, then)
    }

    update(name : string, query : any, data : any, then : any) : void{
        MongDb.CONN.collection(name).updateOne(query, data, then);
    }
    
    delete(name : string, query : any, then : any) : void{
        MongDb.CONN.collection(name).deleteOne(query, then);
    }    
}    

 

insert, update, delete 함수를 추가하여 보았습니다.

이를 호출하는 클래스 입니다.

* 파일이름 : index.ts

import * as db from './mongoDb'

class MainClass{

    private mongodb;
    
    constructor(){
        mongodb = new db.MongDb();
    }

    runner() {
        //#1. 조회
        mongodb.findOne('컬렉션',{ userId :'admin'}, (fail, succ)=>{
        
        });
        
        //#2. 등록
        mongodb.insert('컬렉션',{userId :'admin2', passWord:'1234', date:new Date(),day:'2020-12-22 11:30:31', number : 5678, array : [1,2,3,4]}, (fail, succ)=>{
                
        })        
        
        //#3. 수정
        mongodb.update('컬렉션',{userId :'admin'},{newData:1234, passWord:'1'}, (fail, succ)=>{
        
        })      

        //#4. 삭제
        mongodb.delete('컬렉션',{userId :'admin'}, (fail, succ)=>{

        });            
    }
}

const main = new MainClass();
main.runner();

 

등록, 수정, 삭제 행뒤 전부 간단하게 Object의 형태(Json)로 넣어주면 됩니다.

스키마(Schema)가 없으니 데이터를 따로 처리할 필요가 없습니다.

aggregate나 find를 통해서 데이터를 n개 이상 가져오는 경우도 비슷하게 사용 가능 합니다.

데이터베이스에 연결하는 최종 클래스의 모습 입니다.

* 파일이름 : mongoDb.ts

import * as mongoose from 'mongoose';

const url = 'mongodb://주소/db이름?minPoolSize=0&maxPoolSize=10';

export class MongDb {
    private static CONS : number;
    private static CONN : mongoose.Connection;

    constructor (){
        if(MongDb.CONS != 1){  //연결이 안된 상태면
            mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }).then( db=>{
                MongDb.CONS = mongoose.connection.readyState || 0;
                MongDb.CONN = db.connection;  //사용할 커넥션!!
            })
        }
    }
    
    findOne(name : string, query : any, then : any) : void{
        MongDb.CONN.collection(name).findOne(query, then)
    }
    
    insert(name : string, data : any, then : any): void{
        MongDb.CONN.collection(name).insertOne(data, then)
    }

    update(name : string, query : any, data : any, then : any) : void{
        MongDb.CONN.collection(name).updateOne(query, data, then);
    }
    
    delete(name : string, query : any, then : any) : void{
        MongDb.CONN.collection(name).deleteOne(query, then);
    }    
    
    aggregate(name : string, query : Object[], then : any) : void{
        MongDb.CONN.collection(name).aggregate(query).toArray(then)
    }    
    
    findPaging(name : string, query : any, skip :number = 0, limit : number = 10, then : any) : void {
        MongDb.CONN.collection(name).find(query).skip(skip).limit(limit).toArray(then);
    }    
}    

 

aggreagte 함수와, findPaging이라는 함수를 추가 하였습니다.

aggreagte 함수에서 질의를 하는 부분은 배열 형태의 Object 입니다.

두개의 함수 마지막에 toArray 함수를 실행한 뒤에 화살표 함수를 넣어 결과를 볼 수 있도록 하였습니다.

위 코드를 실행하는 최종 모습입니다.

* 파일이름 : index.ts

import * as db from './mongoDb'

class MainClass{

    private mongodb;
    
    constructor(){
        mongodb = new db.MongDb();
    }

    runner() {
        //#1. 조회
        mongodb.findOne('컬렉션',{ userId :'admin'}, (fail, succ)=>{
        
        });
        
        //#2. 등록
        mongodb.insert('컬렉션',{userId :'admin2', passWord:'1234', date:new Date(),day:'2020-12-22 11:30:31', number : 5678, array : [1,2,3,4]}, (fail, succ)=>{
                
        })        
        
        //#3. 수정
        mongodb.update('컬렉션',{userId :'admin'},{newData:1234, passWord:'1'}, (fail, succ)=>{
        
        })      

        //#4. 삭제
        mongodb.delete('컬렉션',{userId :'admin'}, (fail, succ)=>{

        });      
        
        //#5. 집계
        var operation = [  //aggregate 샘플 입니다. 몽고DB 쿼리와 동일 합니다.
            { $project : {'userId' : '$userId', 'passWord':'$passWord', 'number':'$number' }},
            { $match : { 'userId' : {$regex : 'roo' }  } },
            { $group: { "_id": { userId: "$userId", passWord: "$passWord" }, 'counts':{$sum : 1}, 'total':{$sum : '$number'}, 'texts':{$addToSet : '$userId' }   } },
            { $sort : {'_id':-1} }
        ];
        mongodb.aggregate('컬렉션', operation, (fail, succ)=>{

        });

        //#6. 페이징이 존재하는 조회
        mongodb.findPaging('컬렉션', {}, 0, 2, (fail, succ)=>{

        })        
        
    }
}

const main = new MainClass();
main.runner();

 

실제 동작 모습 입니다.

잘 나오는군요~

 

커넥션(Connection) 클래스에 존재하는 컬렉션(collection) 객체를 통해서 작업 하는 것은 스키마를 정의하지 않아도 되기 때문에 작업 속도가 조금 더 빠르다고 생각 합니다.  * 주관적인 의견 입니다!

저장 해야될 데이터(도큐먼트)의 키(key)값이 변하더라도 수정을 하지 않아도 되는 장점을 지니고 있습니다.

그러나 스키마를 정의하는 부분이 없기 때문에 엄격한 데이터 관리는 다소 어렵습니다.

 

이상으로 Node.js에서 몽고DB를 연결하여 사용하는 방법 중 한가지인 커넥션(Connection) 클래스 사용법에 대해서 살펴 보았습니다!

궁금한 점이나 틀린점은 언제든지 연락주세요. ^^

 

* package.json

{
  "name": "backpj",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "tsc && node dist"
  },
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "mongoose": "^5.11.8",
    "typescript": "^4.1.3"
  }
}

* tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "moduleResolution": "node",
    "outDir": "dist/"
  },
  "include": [
    "src/*"
  ]
}

 

 

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글