221124 Node.js #11

김혜진·2022년 11월 24일
0

Node.js

목록 보기
11/13

MongoDB Atlas


검색

server.js

app.get("/search", (req, res) => {
    db.collection('post').find({todo: req.query.value}).toArray((err, result) => {
        if(err) return console.log(err);
        console.log(result);

        res.render('search.ejs', {posts : result});
    });
});

list.ejs

검색바 추가

    <div class="container input-group mb-2">
      <input class="form-control" id="search-input"/>
      <button class="input-group-append btn btn-danger" id="search">검색</button>  
    </div>

    <script>
      $('#search').click(function() {
        let inputValue = $('#search-input').val();
        window.location.replace('/search?value=' +  inputValue); // 현재 url 뒤에 붙여줄 것
      })
    </script>

search.ejs

<h1 class="ml-2 my-3 text-center">검색결과</h1>

    <div class="container">
      <ul class="list-group">
        <% for (let i = 0; i < posts.length; i++) { %>
        <li class="list-group-item">
          <p>글번호 : <%= posts[i]._id %></p>
          <a href="/detail/<%= posts[i]._id %>"><h4>할일 제목 : <%= posts[i].todo %></h4></a>
          <p>날짜 : <%= posts[i].date %></p>
          <button class="btn btn-danger delete" data-id="<%= posts[i]._id %>">삭제</button><p></p>
        </li>
        <% } %>
      </ul>
    </div>

    <script>
      $('.delete').click(function(e) {
        var btnClick  = $(this);

        $.ajax({
          method : 'DELETE',
          url : '/delete',
          data : {_id : e.target.dataset.id} // 삭제할 게시물 번호
        }).done(function(result){
          // 요청 성공 시 실행
          console.log('삭제성공')
          // 삭제 대상을 안보이게 처리하는 루틴
          btnClick.parent('li').fadeOut();

        }).fail(function(xhr, textStatus, errorThrown) {
          // 요청 실패 시 실행
          console.log('삭제실패')

        })
      })
    </script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script>
  </body>
</html>


하지만 키워드를 모두 정확하게 입력하지 않으면 검색이 안됨

순차검색은 맨 처음부터 끝까지 순차적으로 찾아야하기 때문에 데이터가 많아질수록 효율이 떨어진다.

검색은 이분검색, 정렬은 버블정렬, 퀵정렬

mongoDB의 post 컬렉션에 Create Index.

type에 string이 아니라 text로 적어야한다. (문법임)
1로 적으면 숫자로 인식한다.

app.get("/search", (req, res) => {
    // ────────────────── 일반적인 순차검색 ──────────────────
    // db.collection('post').find({todo: req.query.value}).toArray((err, result) => {
    //     if(err) return console.log(err);
    //     console.log(result);

    //     res.render('search.ejs', {posts : result});
    // });


    // ────────────────── 바이너리 검색 ──────────────────
    db.collection('post').find({$text : {$search : req.query.value}}).toArray((err, result) => {
        if(err) return console.log(err);
        console.log(result);

        res.render('search.ejs', {posts : result});
    });
});


키워드에 해당되는 것 모두 검색된다.


passportjs.org

자신이 작성한 글만 삭제

글 작성 시 작성한 유저의 아이디를 불러온다.
passport를 통해 로그인 시 받아오는 user의 정보를 활용한다.

  • 글 작성 함수 안 insertOne에 writer 항목을 추가한다.
db.collection('post').insertOne({_id: totalCount + 1, writer : req.user._id , todo: req.body.title, date: req.body.date}, function(err, result) {
  if(err) return console.log(err);
  console.log('저장완료');
});
  • 삭제 함수 안에 writer 항목과 _id 항목을 deleteData로 저장 후 전달해 일치하는 글 데이터를 삭제한다.
app.delete('/delete', function(req, res) {
    console.log(req.body)
    req.body._id = parseInt(req.body._id);

    var deleteData = {_id : req.body._id , writer : req.user._id}

    db.collection('post').deleteOne(deleteData, function(err) {
        if(err) return console.log(err);
        console.log('삭제완료');
        res.status(200).send({message: '성공'})
    })
})

list.ejs

<script>
  $('.delete').click(function(e) {
  var btnClick  = $(this);

  $.ajax({
    method : 'DELETE',
    url : '/delete',
    data : {_id : e.target.dataset.id} // 삭제할 게시물 번호
  }).done(function(result){
    // 요청 성공 시 실행
    console.log('삭제성공')
    // 삭제 대상을 안보이게 처리하는 루틴
    btnClick.parent('li').fadeOut();
    location.reload();

  }).fail(function(xhr, textStatus, errorThrown) {
    // 요청 실패 시 실행
    console.log('삭제실패')

  })
})
</script>

삭제버튼을 클릭하면 데이터베이스에서 삭제가 되지 않아도 fadeOut 효과때문에 화면에서 사라지게 되므로 location.reload()를 붙여서 새로고침을 시킨다.
그러면 사라지지 않은 데이터는 그대로 남아있게 된다.


라우터 분리

코드를 작성하고 보니 server.js의 코드가 너무 길어졌다.

server.js

// 라우트 미들웨어 설정
app.use('/', require('./routes/webtoon.js'));

routes/webtoon.js

var router = require('express').Router();

router.get('/webtoon/drama', (req, res) => {
    res.send('웹툰의 드라마입니다.');
})

router.get('/webtoon/action', (req, res) => {
    res.send('웹툰의 액션입니다.');
})

module.exports = router;

app.use를 사용하면 전역 미들웨어가 된다.

부분 미들웨어는 아래 isLogin 같이 요청이 들어왔을때만 사용하는 미들웨어다.

app.get('/mypage', isLogin, (req, res) => {
    res.render('mypage.ejs', {사용자 : req.user});
});
function isLogin(req, res, next) {
    if(req.user) {
        next(); // 다음으로 넘어감
    } else {
        res.send('로그인 해주세요.');
    }
}

사용자가 / 루트로 요청을 했을때 하위 루트를 적용해달라는 의미이다.

server.js

/webtoon으로 요청을 했다면

app.use('/webtoon', require('./routes/webtoon.js'));`

routes/webtoon.js

앞의 /webtoon을 제외하면 된다.

router.get('/drama', (req, res) => {
    res.send('웹툰의 드라마입니다.');
})

데이터베이스와 함께 이동 (routes/list.js)

var router = require('express').Router();

var db;
const mongoClient = require('mongodb').MongoClient;
mongoClient.connect(
    process.env.DB_URL,

    function(err, client) {
    if(err) return console.log(err);

    db = client.db('TodoApp');
})
// list get 요청(페이지를 보여줘라)으로 접속하면
// 실제 DB에 저장된 데이터들로 예쁘게 꾸며진 HTML 보여주세요.

router.get('/list', function(req, res) {
    // find()함수는 DB에서 모든 데이터를 가져와서 문자열로 변경
    db.collection('post').find().toArray(function(err, result) {
        // console.log(result);
        res.render('list.ejs', {posts : result});
    });
})

module.exports = router;

로그인 조건 걸기

부분 미들웨어를 사용한다.

routes/webtoon.js

var router = require('express').Router();

router.get('/drama', isLogin, (req, res) => {
    res.send('웹툰의 드라마입니다.');
})

router.get('/action', isLogin, (req, res) => {
    res.send('웹툰의 액션입니다.');
})


function isLogin(req, res, next) {
    if(req.user) {
        next(); // 다음으로 넘어감
    } else {
        res.send('로그인 해주세요.');
    }
}

module.exports = router;

로그인을 해야만 접근할 수 있는 페이지가 된다.
하지만 일일이 isLogin을 걸어주는 것이 번거로우므로 전역변수로 만들어준다.

router.use(isLogin)

routes/webtoon.js

var router = require('express').Router();

router.use(isLogin)

router.get('/drama', (req, res) => {
    res.send('웹툰의 드라마입니다.');
})

router.get('/action', (req, res) => {
    res.send('웹툰의 액션입니다.');
})


function isLogin(req, res, next) {
    if(req.user) {
        next(); // 다음으로 넘어감
    } else {
        res.send('로그인 해주세요.');
    }
}

module.exports = router;

제한적인 페이지에 걸기

router.use('/drama', isLogin);

이미지

업로드

npm install multer

Multer는 파일 업로드를 위해 사용되는 multipart/form-data 를 다루기 위한 node.js 의 미들웨어.
multipart (multipart/form-data)가 아닌 폼에서는 동작하지 않는다.

server.js

// ────────────────── multer 설정 ──────────────────
let multer = require('multer');

let storage = multer.diskStorage({
    destination : function(req, res, cb) {
        cb(null, './public/image')
    },
    filename : function(req, file, cb) {
        cb(null, file.originalname) // file.originalname : 파일 이름을 그대로 사용
    }
});

let upload = multer({storage : storage});

app.get('/upload', function(req, res) {
    res.render('upload.ejs');
})

app.post('/upload', upload.single('profile'), function(req, res) {
    res.send('업로드 완료');
})

public/image 폴더에 업로드 된 이미지를 저장한다.

upload.ejs

<h2 class="container mt-4"><strong>이미지 파일 업로드</strong></h2>
    
    <div class="container mt-3">
      <form action="/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="profile" />
        <button type="submit">전송</button>
      </form>
    </div>

출력

server.js

app.get('/image/:imgname', function(req, res) {
    res.sendFile(__dirname + '/public/image/' + req.params.imgname);
})

주소창에 경로를 입력하면 사진이 출력된다.

profile
알고 쓰자!

0개의 댓글