🎯 Achievement Goals


  • NoSQL의 장점 및 특징에 대해서 이해할 수 있다.
  • Mongo DB 연결





👉 NoSQL


오늘은 NoSQL중에서도 대표적인 MongoDB에 대해서 공부를 하였다. 상황에 따라서 SQL을 사용하거나 NoSQL을 사용하는데, 관계형 테이블의 레거시한 방법을 사용하지 않는 데이터 저장소를 NoSQL이라고 한다.

즉, NoSQL은 데이터베이스에서는 데이터를 행과 열이 아닌 체계적인 방식으로 저장을 하며, MongoDB에서 데이터는 도큐먼트 형태로 저장되고 도큐먼트드은 컬렉션이라는 곳에 저장된다. 그래서 Mongo DB도큐먼트 데이터베이스라고도 불린다.



NoSQL 기반의 데이터베이스를 사용하는 경우

  1. 데이터의 구조가 거의 없는 또는 대용량의 데이터를 저장해야 하는 경우

  2. 클라우드 컴퓨팅 및 저장공간을 최대한 활용하는 경우

  3. 빠르게 서비스를 구축하고 데이터 구조를 자주 업데이트 하는 경우

여담으로 오늘 수업중에서 SQL과 NoSQL을 각각 써야 하는 경우가 궁금하다는 질문이 있었다. 엔지니어님의 답변이 인상깊었는데, 만약 인스타그램에서 좋아요를 눌렀는데 1이 일시적으로 증가를 안하는 것에 대해서 무슨 큰 일이 일어나거나 하진 않는다.

하지만 은행과 같이 결제 시스템에서 조그마한 결제 실수라도 있는 날에는 난리가 난다. 그래서 정확한 데이터베이스를 요구해야 할 때는 SQL, 인스타그램 같이 빠른 업로드를 필요할 경우는 NoSQL을 쓰면 된다고 하셨다. 물론 우리가 만드는 웹사이트의 규모는 어느것을 써도 상관없고 요새는 둘 다 쓰는 경우가 있기 때문에 둘 다 잘 아는 것이 중요하다고 하셨다.




👉 Monge DB


오늘은 Mongo DB에 대해서 스스로 학습하는 것이 과제였는데, 나는 Mongo DB를 설치하고 연결하는 것을 연습했다. 그리고 로그인 요청을 했을 때 실제로 Mongo DB에서 데이터를 받는 것 까지 해보았다

먼저 Mongo DB를 사용하기 위해 이것저것 필요한 것들을 설치를 해주었다.


$ npm i express --save
// 재시작 할 필요 없는 데브툴
$ npm i nodemon --save-dev
// 몽고디비를 더 편리하게 사용하게 해주는 툴
$ npm i mongoose --save


그리고 Mongo DB에 회원가입을 하고 소스코드를 받아 환경변수에 저장을 해주었다. 그 후에 mongoose 를 활용하여 쉽게 연결할 수 있었다!

// config/prod.js
module.exports = {
    mongoURI: process.env.NODE_URI
}

//index.js
const mongoose = require('mongoose');
mongoose.connect(config.mongoURI, {
    useNewUrlParser: true, useUnifiedTopology: true, 
    useCreateIndex: true, useFindAndModify: false
}).then(() => console.log('mongo'))
  .catch(err => console.log(err));


이제 post 요청으로 registerlogin을 데이터베이스로 날려주었는데, 그 전에 스키마를 만들고 PostMan을 활용하여 수동작업을 통해 Mongo DB에서 데이터를 받는 것을 실시간을 보았다.



register post 요청


//models.js
const userSchema = mongoose.Schema({
    name: {
        type: String,
        maxlength: 50
    },
    email: {
        type: String,
        trim: true,     // 공백제거
        unique: 1       // 중복 사용을 못하게 한다.
    },
    password: {
        type: String,
        minlength: 5
    },
    lastname: {
        type: String,
        maxlength: 50
    },
    role: {
        // 어떤 유저가 관리자가 될 수 도 있고, 일반 유저가 될 수 도 있다.
        type: Number, // 넘버가 1이면 관리자, 0이면 일반유저
        default: 0    // 기본값
    },
    image: String,    // 오브젝트 사용안하고 string으로 바로 쓸 수 있음
    token: {
        type: String  // 유효성 관리
    },
    tokenExp: {
        type: Number   // 토큰 유효기간
    }
});

// index.js

app.post("/api/users/register", (req, res) => {
    
    // 회원 가입 할 때 필요한 정보들을 client에서 가져오면 
    // 그것들을 데이터 베이스에 넣어준다

    // instance를 만든다.
    // 클라이언트에 입력된 정보를 데이터베이스에 넣기 위함.
    const user = new User (req.body)
    // req.body 안에는 json 형식으로 데이터가 들어있다.
    // 이렇게 해줄 수 있는 이유는 위에 이미 body-parser를 다운로드 받았기 때문

    user.save((err, userInfo) => {
        // 저장할 때 에러가 있으면 클라이언트에 json 형태로 전달 (메세지도 같이 전달)
        if(err) return res.json({ success: false, err });
        // status(200) 은 성공했다는 뜻 (에러X)
        return res.status(200).json({
            success: true
        })
    })
})


PostMan

posr


Mongo DB

mongo



Login post 요청

이번에는 login을 요청하고 비밀번호는 bcrypt를 활용하여 비밀번호를 안보여주기 위해 해쉬값으로 바꿔주었다. 그리고 jsonwebtokencookieParser를 활용하여 토큰을 전달하고 쿠키에 저장하는 것 까지 해보았다!


// models.js
userSchema.methods.comparePassword = function(plainPassword, cb) {
    // cb => call back function이라는 뜻
    // plainPassword 는 1234567 이고, 데이터베이스에 있는 암호화된 비밀번호랑 맞는지 체크를 해야한다.
    // 그래서 plainPassword를 암호화해서 비교해야한다.
    bcrypt.compare(plainPassword, this.password, function(err, isMatch) {
        // 비밀번호가 같지 않다면
        if(err) return cb(err);

        // 비밀번호가 같다면 err는 없으니까 => null로 표시하고, 
        //isMatch가 true 라는 뜻
        cb(null, isMatch);
    })
}

userSchema.methods.generateToken = function(cb) {
    // jsonwebtoken 을 이용해서 token을 생성하기

    // user._id 는 데이터베이스에 있는 id
    // toHexString으로 에러를 없애준다?
    let token = jwt.sign(user._id.toHexString(), "secretToken")

    user.token = token
    user.save(function(err, user) {
        // err가 있다면 콜백으로 에러 전달
        if(err) return cb(err)
        // save가 잘 되었으면 null로 에러없다는 표시하고 
        // user 정보를 index.js로 전달
        cb(null, user)
    })
}

// index.js
app.post("/api/users/login", (req, res) => {
  
  // 1. 요청된 이메일(아이디)을 데이터베이스에서 있는지 찾는다.

  User.findOne({ email: req.body.email }, (err, user) => {
    // email을 가진 유저가 한 명도 없다면, userInfo가 없다는 뜻이니
    if (!user) {
      return res.json({
        loginSuccess: false,
        message: "제공된 이메일에 해당하는 유저가 없습니다."
      })
    }

    // 2. 요청된 이메일이 데이터 베이스에 있다면 비밀번호가 맞는 비밀번호 인지 확인.
    
    // user에는 이름,비번,이메일이 담겨 있고, comparePassword를 만든다.
    // req.body.password < 요청할 때 주는 패스워드.
    // 입력한 비밀번호랑 데이터베이스 비밀번호가 같으면 isMatch로 맞는지 가져온다.

    user.comparePassword(req.body.password, (err, isMatch) => {
      if (!isMatch)
        return res.json( { loginSuccess: false, 
                           message: "비밀번호가 틀렸습니다."})

      // 3. 비밀번호 까지 맞다면 토큰을 생성하기
        user.generateToken((err, user) => {
          // 토큰 생성을 위해서 JSONWEBTOKEN 라이브러리를 이용해야 한다.

          // 에러가 있다면 status(400) 은 에러가 있다는 표시
          if (err) return res.status(400).send(err);

          // 쿠키에다가 저장을 하려면 라이브러리를 다운로드 받아야함
          res.cookie("x_auth", user.token)
          .status(200)  // 성공했다는 표시
          .json({ loginSuccess: true, userId: user._id })  
          // json으로 데이터를 보내준다.
        })
    })
  })
})


PostMan

moggon


Mongo DB

token









🙌 느낀점


오늘은 혼자서 Mongo DB를 공부하는 게 과제였다. 그래서 강의를 통해서 Mongo DB를 공부했는데, 도중에 에러를 많이 만나서 생각보다 오래걸렸다 ㅜㅜ 그래도 시간을 많이 투자한 결과 오늘 하루만에 회원가입 요청과 로그인 요청을 해보았다!! 완전 집중하는 바람에 시간이 빨리갔다.

그리고 시간이 부족해서 오늘은 오전에 못풀었던 토이문제를 풀지 못할 것 같다 ㅜㅜ 이번주 토요일까지 프로젝트 팀원 각자 타입스크립트로 아무거나 만들어오는게 과제인데.. 아직 시작도 못했다 ㅜㅜㅜㅜ

리액트 + 타입스크립트로 슬렉 클론 코딩을 할 예정인데.. 다음주까지는 할 수 있을지 의문이 든다. 무엇보다도 학습효과가 좋았으면 좋겠다!!





👊 내일의 TIW(today I Will)

Token