ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 2023 - 06 - 17 MongoDB, Mongoose, 몽구스, Schema 스키마, model, populate, Queries 쿼리
    Today I Learned/TIL 06 2023. 6. 17. 11:33

     
    NoSQL 데이터베이스로 분류되는 MongoDB는 가장 유명한 NoSQL데이터베이스 시스템이다.
     
    Mongoose

     
    Mongoose는 Node.js와 MongoDB를 연결해주는 ODM이다.
    **ODM(Object Document Mapping) : 객체와 문서를 1대1로 매칭하는 역할
    MongoDB의 ODM은 다양하지만 Mongoose가 가장 유명하다.
     
     

    패키지 설치


    npm install mongoose --save
    yarn add mongoose

    위와 같이 노드 패키지 매니저 npm 혹은 yarn을 통해 설치할 수 있다.
     

    MongoDB 연결하기 (둘중 하나)


    1) require을 이용하는 방법

    const mongoose = require('mongoose');
    mongoose.connect("mongodb://lodcallhost/<db이름>", 
    {useNewUrlParser: true});

    2) import를 이용하는 방법

    import mongoose from 'mongoose';
    
    mongoose.connect('mongodb://localhost/<db이름>',
    {useNewUrlParser: true});

     

     

    우선 mongoose 모듈을 require(혹은 import)해준다. 그 이후 connect 메소드를 통해 MongoDB에 연결한다.
     
    connect 메소드의 인자로는 mongdodb url(기본적으로는 localhost를 사용.) 과 useNewUrlParser와 같이 error발생하지 않도록 다른 인자들을 객체 형식으로 선언한다.
     
    만약 본인만의 mongoDB 서버가 있으면, url인자에 'mongodb://username:password@host:port/database'  를 보내면 된다.
     
     

    Schema 생성하기


    Mongoose는 Schema라는 개념이 존재한다.  MongoDB의 경우 Document에 데이터를 아무거나 막 넣어도 에러가 발생하지 않는다. 이는 양날의 검과 같은데, 데이터를 막 넣을 수 있기에 편리하지만 반대로 불필요한 데이터 같은 데이터도 다 들어가며, 어떤 경우엔 원하는 자료형과 맞지 않는 데이터가 들어갈 수도 있는 문제가 있다.
     
    그래서 Mongoose는 Schema를 도입한 것. 스키마는 SQL의 table과 비슷한 개념이다. 데이터를 넣을 때 schema에서 선언한 틀에 맞게 데이터를 넣을 수 있도록 해준다.
     
     

    import mongoose from 'mongoose';
    
    const imageSchema = new mongoose.Schema({
      width : Number,
      height : Number,
    });
    
    const developersSchema = new mongoose.Schema({
      name : {type : String, required: true},
      age : {type : Number, required: true},
      image : imageSchema,
      nickname : String,
      language : String,
      friends : [String],
    });

     
     
    스키마는 위와 같이 mongoose를 import 한 뒤, new mongoose.Schema({});를 통해 생성 가능
     
    필드를 하나씩 살펴보면
    name은 String타입이며, required : true를 통해 꼭 필요한 값으로 지정.
    age는 Number타입이며, 이 또한 required : true를 통해 필요한 값으로 지정.
     
    image필드는 다른 필드와 조금 다르게 선언되었는데, imageSchema라고 지정되어있다.
    이는 image필드는 imageSchema라는 또 다른 스키마를 타입으로 가진다.
    풀어서 보면
     
    image : { width : Number,
                height : Number,
               } 
     
    nickname은 String타입으로 선언되었다. (language도 동일!)
    friends는 String타입의 배열로 선언되었다.
     
     
    스키마를 만든뒤 데이터베이스 서버로 쏙 넣어준다

    import mongoose from 'mongoose';
    
    const imageSchema = new mongoose.Schema({
      width : Number,
      height : Number,
    });
    
    const developersSchema = new mongoose.Schema({
      name : {type : String, required: true},
      age : {type : Number, required: true},
      image : imageSchema,
      nickname : String,
      language : String,
      friends : [String],
    });
    
    const model = mongoose.model('Developer',developerSchema);

    데이터베이스 서버로 넣어주기 위해서는 구현해놓은 schema를 model 메소드를 통해 객체로 만들어주어야 한다.
    따라서 model이라는 객체를 생성한 뒤, 그 객체에 스키마 model을 넣어준다.
     
    이후 각자 원하는 서버에 올리면 됨.
     
     

    Populate 사용하기


     
     
     MongoDB 스키마를 만들다 보면, 필드 내에 다른 다큐먼트의 ObjectID를 쓰는 경우가 있다.
     
     

    const mongoose = require('mongoose');
    const Schema = mongoose.Schema;
    
    const personSchema = Schema({
      _id: Schema.Types.ObjectId,
      name: String,
      age: Number,
      stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
    });
    
    const storySchema = Schema({
      author: { type: Schema.Types.ObjectId, ref: 'Person' },
      title: String,
      fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
    });
    출처 : https://mongoosejs.com/docs/populate.html

     
    위의 _id와 stories를 보면 타입으로 Schema.Types.ObjectId가 지정되어있다.
    MongoDB에서는 데이터가 차곡차곡 쌓일 때, 그 데이터 하나하나를 document라고 한다.
    _id와 stories는 그 document를 가리키는 타입인 것.
     
     

     { _id: {$oid : 5a23c1b5d52a003c98e13f1c},
      name: 'CharmSae',
      age: 16, 
      stories : {$oid :5a23c1b5d52a003c98e13f1b},
      }

    이런 형식으로 데이터가 조회되고, _id와 stories에 document id값이 저장이 되어있다.
    Populate는 간단하게 말해서 이런 id값을 펼쳐서 보여주는 기능
     
    사용과 그에 따른 결과는 다음과 같다.

    Person.findOne({ name: 'charmsae' }).populate('stories').exec((err, data) => {
      console.log(data);
    }); 
    
    
     { _id: {$oid :5a23c1b5d52a003c98e13f1c},
      name: 'CharmSae',
      age: 16, 
      stories : {
          author : {$oid :5a23c1b5d52a003c98e13f1d},
          title : 'HueMoneLabStory'
          fans : {$oid :5a23c1b5d52a003c98e13f1d},
      	},
      }

    위의 결과랑은 다르게 stories에 어떠한 document가 출력이 되었다,
    이렇게 populate를 활용하면 Schema.Types.ObjectId가 참조하는 다른 document를 조회할 수 있다
     
    하지만 populate를 남발하는 것은 좋지 않다. populate는 $oid값을 조회한 뒤 자바스크립트에서 합쳐주는 것이지 DB 자체에서는 합쳐지지 않기에 성능이 좋은 편은 아니기 때문
     
     

    Queries


    데이터를 조회하는 방식인 Query
    Mongoose에는 다양한 Query가 존재하는데 그중 대표적인 것들만 정리했다.

    더 자세한 Query는 mongoose 공식 사이트를 참고 https://mongoosejs.com/docs/queries.html

    findOne()

    const query = Person.findOne({name : 'charmsae'});
    //Person이라는 컬렉션 안에서 name이 charmsae인 documents를 '하나'불러옵니다.
    

    find()

    const query = Person.find({name : 'charmsae'});
    //Person이라는 컬렉션 안에서 name이 charmsae인 documents를 '모두' 불러옵니다.

     
    deleteOne()

    const query = Person.deleteOne({name : 'charmsae'});
    //Person이라는 컬렉션 안에서 name이 charmsae인 documents를 '하나' 삭제합니다.

    deleteMany()

    const query = Person.deleteMany({name : 'charmsae'});
    //Person이라는 컬렉션 안에서 name이 charmsae인 documents를 '모두' 삭제합니다.

    이때, One이 들어간 쿼리문은 가장 처음 조회되는 document를 불러온다.
     
     
    sort()

    const query = Person.find({name : 'charmsae'}).sort(age : -1);
    //Person이라는 컬렉션 안에서 name이 charmsae인 모든 document를 age순으로 정렬합니다.
    //이때, age : 1이면 오름차순, age : -1이면 내림차순으로 정렬합니다.

     
    select()

    const query = Person.findeOne({name : 'charmsae'}).select('age');
    //Person이라는 컬렉션 안에서 name이 charmsae인 documents를 '하나' 조회한 뒤,
    // age 필드만 가져옵니다.

     
     
     
     

    MongoDB, Mongoose 아이디 비밀번호 설정


     
     
    일명령 프롬프트에서 mongod라고 입력한다.
    에러가 발생하거나 없다고 뜨시면, mongodb를 먼저 설치하기. (몽고디비 공식사이트)
     

    위와 같이 뜨면 성공
     
    그 뒤에는 명령 프롬포트를 하나 더 띄운 뒤 mongo라고 쓴다

    위와 같이 뜨시면 이제 준비완료, 아래와 같이 작성한다.

    use admin
    db.createUser({ user: '이름', pwd: '비밀번호', roles: [{role : "userAdminAnyDatabase"}] })

    그런 뒤, 다시 mongoose파일로 가서 

    const mongoose = require('mongoose');
    mongoose.connect("mongodb://lodcallhost/<db이름>", 
    {useNewUrlParser: true});

    와 같이 작성한 코드를 다음과 같이 수정한다

    const mongoose = require('mongoose');
    mongoose.connect('mongodb://아이디:비밀번호@호스트:포트/dbname'), 
    {useNewUrlParser: true});

     
     

    댓글

Designed by Tistory.