[Node] Model을 통해 파일에 data 저장하기

silverKi·2023년 12월 22일
0

Node

목록 보기
5/6

제품을 더이상 배열에 저장하지 않고, 파일에 저장하는 것으로 변경해 보겠다.
따라서 save method를 호출시에 파일에 저장하는 로직으로 변경한다.
우선, node core module인 fs(filesSystem)을 import 한다.


//변경전

const products = [];

module.exports = class Product { 
    constructor(t) { //매개변수 : title 
        this.title = t //this.title을 인수로 수신함
        //this == Product 객체를 가리킴
    }
    save() { 
        products.push(this)
    }
    static fetchAll() { 
        return products
    }
}

//변경후 
const fs = require("fs"); //node core module import
const path = require("path"); //경로 구축
module.exports = class Product {
	constructor(t) {
		//매개변수 : title
		this.title = t; //this.title을 인수로 수신함
		//this == Product 객체를 가리킴
	}
	save() {
		const p = path.join(
			path.dirname(require.main.filename),
			"data",
			"products.json"//확장자를 JSON으로 지정하여, data를 json 형식으로 저장
		);
      //새 제품을 저장하기 위해서 기존 제품 배열을 가져온다.
        fs.readFile(p, (err, fileContent) => { 
            console.log(err);
        } )
	}
	static fetchAll() {
		return products;
	}
};

err로그를 보면, products is not defined이 출력된다. 그 이유는 data폴더안에 products.json 파일이존재 하지 않기 때문인데, 나는 존재하지 않더라도 계속 진행하고 싶다.

fs.readFile(p, (err, fileContent) => { 
     let products = [];
     if (!err) { 
        products = JSON.parse(fileContent)
     }
     products.push(this)
     fs.writeFile(p, JSON.stringify(products), (err) => { 
           console.log(err)
      })
 } )

errlog로는 null이 출력돼고, data/products.json 파일이 생성이 되면서, 사용자가 입력한 data값이 기록이 되는 것을 확인하였다.

이제 실행을 해보면, 될 줄 알았는데
TypeError: Cannot read properties of undefined (reading 'length') length문제가 발생한다.

static fetchAll() {
        const p = path.join(
			path.dirname(require.main.filename),
			"data",
			"products.json"
        );
        fs.readFile(p, (err, fileContent) => { 
            if (err) { 
                return [];
            }
            return JSON.parse(fileContent)
        })
		//return products;
	}

fetchAll()에서 return [] , return JSON.parse(fileContent)게 두 경우 모두 data를 반환하고 있지만, 비동기식 코드이기에,
fs.readFile(p, (err, fileContent) => {..}) (err, fileContent) => {..}의 화살표 함수내에 존재하는 return JSON.parse(fileContent)는 안쪽 함수에 포함되는 것이고 fetchAll()에 반환값으로 적용되지 않는것이기 때문에 fetchAll()가 종료된 후에는 아무것도 반환되지 않는것이다. 따라서 undefined인 상태이고


exports.getProduct = (req, res, next) => {
    const products = Product.fetchAll();//저장된 배열내 data call
    res.render("shop", {
        prods: products,
        docTitle: "Shop",
        path: "/",
        hasProducts: products.length > 0,
        activeShop: true,
        productCSS: true,
        
	});
}

products상수에는 undefined의 값이 대입되어 있고, view를 render()시에 정의되지 않은 상태에서 해당 값의 길이를 읽지 못하는 오류가 발생하는 것이다. 이를 해결하기 위해 fetchAll()에 매계변수로 콜백함수를 전달하도록 수정했다. 이제 fetchAll()에 함수를 전달할 수 있게 되고 함수가 끝난뒤 fetchAll()이 함수를 실행한다.

//models/product.js
static fetchAll(cb) {
        const p = path.join(
            path.dirname(require.main.filename),
            "data",
            "products.json"
        );
		fs.readFile(p, (err, fileContent) => {
		if (err) {
			cb([]);
        } else {
            cb(JSON.parse(fileContent));
        }
	});
}

//controllers/products.js
exports.getProduct = (req, res, next) => {
    Product.fetchAll((products) => { 
        res.render("shop", {
            prods: products,
            docTitle: "Shop",
            path: "/",
            hasProducts: products.length > 0,
            activeShop: true,
            productCSS: true,
            
        });
    });//저장된 배열내 data call
}
profile
아악! 뜨거워!!

0개의 댓글