#1 팁1 - mongodb id를 router에 사용할 때, 16진법 24자리 정규표현식으로 사용하기

    videoRouter.get("/:id([0-9a-f]{24})", watch)

     

     

    #2 Query - find vs findOne

    find는 해당 조건에 맞는 모든 요소를 배열로 반환하고, findOne은 하나만 객체로 반환한다.

    또 id로 찾는데 특화된 findById() 도 있다.

     

    이러한 쿼리 메소드들은 만들어둔 model 변수를 통해 사용한다.

    const Document = mongoose.model("Document", documentSchema)

     

    https://mongoosejs.com/docs/queries.html

     

    Mongoose v8.1.1: Queries

    Queries Mongoose models provide several static helper functions for CRUD operations. Each of these functions returns a mongoose Query object. A mongoose query can be executed in one of two ways. First, if you pass in a callback function, Mongoose will exec

    mongoosejs.com

     

     

    #3 .exec() 와 쿼리 예외처리

    쿼리를 실행하는 문장 뒤에 붙이는 메소드로, 반환되는 promise를 받는 함수이다. async await으로 사용할때는 크게 신경쓸 필요는 없지만 promise에서 error를 받는 예외 처리는 당연히 따로 구현해두어야 한다.

     

     

    #4 update 와 간략한 findOneAndUpdate()

    const document = await Document.findOne({title: word});
            
    if(!document){
        return res.render("404", {word: word});
    }
    
    //document 값 수정 생략
    
    await document.save();

    위가 하나를 찾은 뒤, save()로 저장하는 방식이다.

    그러나 mongoose에서는 findOneAndUpdate() 와 같이 검색과 수정, 검색과 삭제 등의 과정을 합쳐놓은 기능들이 있다.

     

    아래는 이를 사용한 예시이다.

     

    export async function postEditDocument(req, res){
        const word = req.params.w;
        const {title, document, category, annotations} = req.body;
    
        try{
        	//404여부를 위해 먼저 찾는 과정을 한번한다. 
            //find대신 exist를 사용한다.
            //const isDoc = await Document.findOne({title: word});
            
            const isDoc = await Document.exists({title: word});
            if(!isDoc){
                return res.render("404", {word: word});
            }
            
            await Document.findOneAndUpdate({title: word}, {
                title: title,
                category: category,
                description: document,
                annotations: annotations,
            });
    
            return res.redirect(`/word/${word}`);
        }
        catch(error){
            return res.render("errorPage", {error: error});
        }
    }

     

    findOne()이 아닌, exists()를 사용하여 예외처리를 한다.

     

     

    #5 Mongoose의 middleware

    데이터를 저장, 업데이트 하기 전, 해당 프로세스를 잠시 중단하고 사용자 지정 함수를 추가할 수 있는게 middleware이다. server의 middleware와 거의 유사한 개념이다. hook이라고 부르기도 한다.

     

    미들웨어 종류 공식문서 - https://mongoosejs.com/docs/middleware.html#middleware

     

    [미들 웨어 생성 방법]

     

    1. 미들웨어는 Model이 생기기 전에 만들어야 한다. 즉, 스키마와 모델 사이에 선언해야 하는 것이다.

     

    2. .pre() method로 middleware를 선언하는데, 첫번째 인자는 minddleware의 역할에 따른 종류를(선택), 두번째 인자는 미들웨어 호출시 실행될 콜백함수를 넣어준다.

    documentSchema.pre('save', async function(){
        this.title="제목은 이걸로 고정됨"
    })

    this 의 경우 저장하고자하는 "document"(mongodb 용어)를 가르킨다.

     

    'save'의 경우 DB에 저장하기 전에 항상 수행된다. 이때 저장은 데이터를 처음 집어넣었을 때만 해당하고,

    update하는 경우는 해당되지 않는다.

    공식 문서에서는 findOneAndUpdate()가 save() hook을 호출하지 않기 때문이라고 되어있다.

    따라서 다음과 같이 다른 미들웨어를 추가해줘야한다.

    documentSchema.pre('findOneAndUpdate', async function(){
        console.log(this);
    })

     

    #6 Static 기능

    Model.function() 에는 다양한 기능들이 있다. Moel.save() Model.find() Model.exists()... 등등.

    이렇게 model에 딸린 기능을 사용자 지정으로 만드는 방식이 있는데 이를 static이라고 한다.

     

    이것도 model 선언 이전, schema 생성 이후 그 사이에 선언해줘야한다. 비유하자면 겉보기에는 model선언이 instance를 할당한 객체이고 그 이전이 class선언 과정 처럼 보인다.

    //idf를 계산하는 static선언
    documentSchema.static('calIdf', function(){
        //사용자 지정 함수
    });
    
    const Document = mongoose.model("Document", documentSchema);
    
    //이제 다른 문서에서도 import만 해주면 사용 가능
    Document.calIdf();

     

    #7 Delete Query

    프로젝트에서는 Model.findOneAndDelete();를 사용했지만 이 외에도 다양하게 있음.

    그리고 Delete와 Remove 두가지가 있는데 차이는 delete를 권장한다고 함. 몽고 DB는 롤백 기능이 없고 비슷한 방식인 oplog 기능을 사용해야 함.

    export async function postDeleteDocument(req, res){
        const PWD = "1234";
        const word = req.params.w;
        const {title, password} = req.body;
    
        if(word != title){
            return res.render("errorPage", {error: {_message:"문서 이름이 같지 않습니다."}});
        }
        if(password != PWD){
            return res.render("errorPage", {error: {_message:"비밀번호가 틀렸습니다."}});
        }
        try{
            const isDoc = await Document.exists({title: title});
            if(!isDoc){
                return res.render("404", {word: title});
            }
    
            await Document.findOneAndDelete({title: title});
            return res.redirect("/");
        }
        catch(error){
            return res.render("errorPage", {error: error});
        }
    }

     

     

    #8  검색 관련 Query

    1. find한 결과들을 정렬하는 sort method

    예를 들어 아래와 같은 상황에서 사용한다.

    const documents = await Document.find({}).sort({createdAt:"desc"});
    //오름차순은 asc

     

    2. 페이지끼리 정보를 주고받는 방법

    req res를 통해 주고 받는 방법은 결국 간단한 방법으로

    req.params

    req.query

    req.body

    3개가 대표적이다.

     

    3. 검색을 사용할 때, 연관 검색 기능을 사용하기 전에는 정규표현식을 사용한 검색을 해보도록 한다.

    //i는 대소문자를 무시하는 ignore, g는 모두 찾는 global이다.
    /query/ig

    mongodb에서 find내부에 정규표현식을 넣어줄 수 있다.

     

    documents = await Document.find({
        title: {
            $regex: new RegExp(`${query}`, "i"),
        },
    });

     

     

    • 네이버 블러그 공유하기
    • 네이버 밴드에 공유하기
    • 페이스북 공유하기
    • 카카오스토리 공유하기