[Node.js] 로그인/회원가입/정보조회 및 수정 기능(MongoDB 사용하기)

아는벌·2023년 2월 22일
1

web (2)

목록 보기
5/20

몽고디비 기본

몽고디비 용어

몽고디비 <- RDBMS

  • COLLECTION <- TABLE
  • DOCUMENT <- ROW
  • FIELD <- COLUMN
  • OBJECT_ID Field <- PRIMARY KEY
  • EMBEDED & LINK <- RELATIONSHIP

몽고디비 사용하기

  • use 데이터베이스명 - 데이터베이스 생성
  • db.getCollectionNames() - 모든 컬렉션 목록 보기
  • db.컬렉션명.drop() - 컬렉션 제거
  • db.dropDatabase() - 현재 DB에서 컬렉션 제거
  • exit - 빠져나오기

데이터 저장

컬렉션에 데이터 저장하기

db.(컬랙션_이름).svae(데이터);

>  db.car.save({name:'SM5', price: 3000, company:'SAMSUNG', year: 2023});
>  db.car.save({name:'SONATA', price:2800, company:'HYUNDAI', year: 2022});
>  db.car.save({name:'BMW', price: 6000, company: 'BMW', year: 2022});
>  db.car.save({name:'K7', price: 5000, company: 'KIA', year: 2023});

find()

db.(COLLECTION_name).find();
=> COLLECTION의 전체 도큐먼트 조회

db.(COLLECTION_name).find().pretty();
=> 들여쓰기한 형태로 도큐먼트 조회

db.car.find({name:'K7'}); - name이 'K7'인 도큐먼트 조회
db.car.find({name:'K7'},{_id:false}); - name이 'K7'인 도큐먼트를 속성 _id를 제외하고 조회

db.car.find({price:{$ gte:2000}},{_id:false}); - 2000이상
db.car.find({price:{$ gt:2000}},{_id:false}); - 2000초과

db.car.find({price:{$ lte:2000}},{_id:false}); - 2000이하
db.car.find({price:{$ lt:2000}},{_id:false}); - 2000미만

db.car.find({price:{$gte:2000}},{_id:false}).count(); - 갯수 반환

db.car.findOne(); - 상위 1개만 반환

db.car.find().sort({name:1}); - 정렬 : name 내림차순
db.car.find().sort({name:-1}); - 정렬 : name 오름차순


_id 속성을 제외하고 조회한다.


name이 K7인 도큐먼트를 _id속성을 제외하고 조회한다.

remove()

remove()를 사용하면 컬렉션 내의 도큐먼트를 제거한다. 메소드의 인자로 제거할 도큐먼트의 조건을 입력할 수 있다.

price가 2800인 도큐먼트를 제거한다.


price가 5000 이상인 도큐먼트를 제거한다.

update()

update()를 사용하면 도큐먼트의 값을 수정할 수 있다.

db.컬렉션명.update( {검색조건}, {$set: 변경할 내용}, 일치하는 항목이 없을 경우 새로 생성 여부, 일치하는 항목이 여러개일때 모두 수정할지 여부 );


db.car.update({name:'K7'},{$set:{price:5000}},false,false);
price가 4000이던 K7의 price가 5000으로 업데이트되었다.


Node.js에서 MongoDB 사용

로그인 기능

// 로그인 처리
router.route('/login').post((req, res) => {
    console.log("POST - /login");
    const userId = req.body.id;
    const userPw = req.body.passwd;
    if(localDB){
        let user = localDB.collection("users").findOne({id: userId, passwd: userPw}, function(err, user){
            if(err) throw err;
            if(user){
                // 세션에 정보를 저장하고 리다이렉트하기
                req.session.user = {
                    id: userId,
                    name: user.name
                }
                res.redirect("/product");
            } else{
                console.log("불일치");
                res.redirect("/longin.html");
            }
        });
    } 
});

데이터베이스에 접속한 후, login.html에서 보낸 id와 pw 데이터가 user 컬렉션 중 id와 passwd가 같은 하나를 조회한다. 그리고 그 결과 데이터가 있다면 세션에 정보를 저장하고 '/product'로 리다이렉트한다. 결과가 없다면 로그인 정보가 없으므로 로그인페이지로 리다이렉트한다.

회원가입 기능

 <h3>회원가입 페이지</h3>
    <form action="/join" method="post">
        <label for="name">Name</label><input type="text" id="name" name="name" value="김김김"><br/>
        <label for="id">ID</label><input type="text" id="id" name="id" value="kim"><br/>
        <label for="pass">PW</label><input type="text" id="pass" name="passwd" value="1234"><br/>
        <input type="submit" value="회원가입">
    </form>

클라이언트 측을 화면과 같이 구성한다. join_form.html의 body 부분 코드이다. '/join'으로 post 요청을 보낸다.

// server.js
// 회원가입
router.route('/join').post((req, res) => {
    console.log("POST - /join");
    const userName = req.body.name;
    const userId = req.body.id;
    const userPw = req.body.passwd;
    let userData = { id: userId, passwd: userPw, name: userName, role:'user' };
    if(localDB){
        let user = localDB.collection("users").insertOne(userData, function(err, result){
            if(err) throw err;
            console.log("데이터 삽입 성공 ㅋ");
            res.redirect("/login.html");
        });
    } 
});

서버에서 '/join' - post 요청을 처리하는 부분이다.
입력 받은 값으로 { id: userId, passwd: userPw, name: userName, role:'user' } 객체 형태의 삽입할 데이터를 선언한다. role은 user로 고정하였다.
users 컬렉션에 데이터를 하나 삽입 할 것이므로 insertOne() 메소드를 사용했다. 데이터 삽입 후엔 로그인 페이지로 리다이렉트했다.

테스트하다보니 같은 데이터가 중복해서 들어갔다..
중복 체크 부분도 추가해야겠다.

// 회원가입
router.route('/join').post((req, res) => {
    console.log("POST - /join");
    const userName = req.body.name;
    const userId = req.body.id;
    const userPw = req.body.passwd;
    
    if(localDB){
        let user = localDB.collection("users").findOne({id: userId}, function(err, user){
            if(err) throw err;
            if(user){
                res.writeHead(200, {"Content-Type": "text/html; charset=utf8"});
                res.write("이미 사용 중인 아이디입니다 :( ");
                res.write('</br> <a href="/login.html">로그인</a>');
                res.write(' <a href="/join_form.html">회원가입</a>');
                res.end();
            } else{
                let userData = { id: userId, passwd: userPw, name: userName, role:'user' };
                localDB.collection("users").insertOne(userData, function(err, result){
                    if(err) throw err;
                    console.log("회원가입 성공 :D");
                    res.redirect("/login.html");
                });
            }
        });
    } 
});

localDB.collection("users").findOne({id: userId}, 먼저 입력된 아이디로 조회를 하고 조회된 데이터가 있다면 이미 사용중인 아이디이다.
조회된 데이터가 없다면 insertOne을 수행하여 데이터를 추가한다.

실행화면

내 정보 조회 기능

router.route("/users/user_detail").get( (req, res)=>{
    res.writeHead(200, {"Content-Type":"text/html; charset=utf8"});
    if(localDB ){
        localDB.collection("users").findOne({id: req.session.user.id}, function(err, user) {
            if(err) throw err;
            if(user){
                req.app.render("users/user_detail", { user}, function(err, html) {
                if(err) throw err;
                res.end(html);
            });
            }
        });
    }
});

현재 로그인된 유저의 id를 세션에서 user.id로 받아온다. 그리고 users 컬렉션에서 findOne({id: req.session.user.id}으로 id가 해당 유저의 아이디를 가진 데이터를 user로 가져온다. views/users/user_detail.ejs에 user를 user이름으로 보내주고 그 결과를 res.end(html)로 처리한다.

실행화면

비밀번호 변경

router.route('/users/update/passwd').post((req, res) =>{
    let oldPasswd = req.body.oldPasswd;
    let newPasswd = req.body.newPasswd;
    console.log(req.session.user.id , oldPasswd);
    if(localDB ){
        localDB.collection("users").findOne({id: req.session.user.id, passwd: oldPasswd}, function(err, user) {
            if(err) throw err;
            if(user){
                localDB.collection("users").updateOne( {id: req.session.user.id},{$set:{passwd : newPasswd}}, function(err, result) {
                    if(err) throw err;
                    res.redirect('/users/user_detail');
                }); 
            } else{
                res.writeHead(200, {"Content-Type":"text/html; charset=utf8"});
                res.write("비밀번호 변경에 실패하였습니다 :( ");
                res.write('<a href="/users/user_detail"> My Page </a>');
                res.write('<a href="/product"> 상품페이지 </a>');
                res.end();
            }
        });
    }
 });

로그인된 유저의 아이디를 세션에서 받아오고 입력된 oldPassswd를 passwd로 하는 데이터가 users 컬렉션에 있는지 찾고 있다면 해당 유저의 id를 id를 가진 데이터의 passwd를 newPasswd로 업데이트하였다.
원래 localDB.collection("users").updateOne( {id: req.session.user.id, passwd: oldPasswd},{$set:{passwd : newPasswd}} 으로 한 번에 처리하고 싶었는데 변경이 정상적으로 완료되었을 때와 아닐때의 조건을 아직 알지못했다.


cmd에서 updateOne를 했을때 실패했을때 modifiedCount :0, matchedCount: 0이였고, 성공했을 땐(일치하는 데이터가 하나임) 각각이
1로 나왔다.

localDB.collection("users").updateOne( 
  {
    id: req.session.user.id,
    passwd: oldPasswd
  },
  {
    $set:{passwd : newPasswd}
  },
  function(err, result) {
    console.log(result)
  });

그리고 server.js에서 console.log(result)을 하면 아래 사진과 같이 출력되었다. modifiedCount와 matchedCount 접근방법을 달리하면 될 것같은데 잘 안된다,, 그래서 일단 따로 처리하지않고 코드를 작성하였다.
그래도 localDB.collection("users").findOne({id: req.session.user.id, passwd: oldPasswd}의 if(user)안에 업데이트 코드를 넣었으므로 현재비밀번호 일차해야하는 조건은 확실히 처리되었다.

실행화면



로그인 시 id hong의 passwd는 1234였으나 비밀번호 수정 후 1111이 되었는 것을 확인 할 수 있다.

0개의 댓글