PROGRAMING/FULL STACK

[Host] Setting up hosting for MongoDB

donghunl 2024. 3. 28. 04:05
반응형

앱을 게시 할 준비를 하기위해서 할일이 하나 더 있습니다. MongoDB를 개발 환경이 아닌 누구나 엑세스가 가능한 곳으로 호스팅 해야 합니다. MongoDB를 위한 다양한 호스팅 플랫폼중에 여기서는 MongoDB Atlas 소프트웨어의 무료 버전이 일반적으로 작업이 가장 쉽다고 생각하기에 이곳을 사용하겠습니다.

MongoDB Atlas | MongoDB

 

MongoDB Atlas

Get started free. No credit card required.

www.mongodb.com

MongoDB 계정이 없다면 위의 링크를 통해 가입을 해야 합니다. 

 

MongoDB의 Atlas 대시보드에서 블로그를 사용을 위해 새로운 프로젝트를 작성합니다.

 

프로젝트 이름을 정해주고 Next 버튼으로 진행합니다. 여기서는 프로젝트 이름은 Full-Stack Blog Site라고 했습니다.

새로운 멤버가 필요하면 추가를 해주고 Create Project버튼으로 프로젝트를 생성합니다.

프로젝트가 생성되면 왼쪽 메뉴에서 Database를 선택하면 다음과 같이 데이터베이스를 생성할수 있는 버튼이 있습니다.

배포할 데이터베이스 화면이 나옵니다. 여기서 무료 버전에 Cluster 이름을 정해주고 Provider와 함께 Region을 선택하고 Create Deployment버튼으로 데이터베이스를 생성합니다. 현재 저는 서부에 있으므로 Region을 변경해 주었습니다.

데이터베이스 사용자 설정을 해줍니다.  password를 카피한후 Choose a connection method로 진행합니다.

연결 방법은 node를 사용할 것이므로 Drivers선택합니다.

그다음 Review setup steps로 진행합니다.

연결설정이 다 되었습니다.

e

데이터베이스 사용자의 이름과 비밀번호가 생겼으니 프로젝트로 돌아가서 설정을 하겠습니다. 이 설정을 환경 파일에 추가하겠습니다. Back End project에 .env파일을 추가하고 다음과 같이 작성합니다.

환경 설정 파일을 노드 서버가 읽어 들일수 있도록 dotenv package를 설치해 줍니다. 명령어는 다음과 같습니다.

npm install dotenv

설치가 완료되면 이제 .env파일을 사용할수 있게 package를 server.js에 import 시켜줍니다.

server.js

import fs from 'fs';
import path from 'path';
import admin from 'firebase-admin';
import express from 'express';
import 'dotenv/config'; // add for .env
import { db, connectToDb } from './db.js';

import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const credentials = JSON.parse(
    fs.readFileSync('./credentials.json')
);
admin.initializeApp({
    credential: admin.credential.cert(credentials),
});

const app = express();
app.use(express.json());
app.use(express.static(path.join(__dirname, '../build')));

app.get(/^(?!\/api).+/, (req, res) => {
    res.sendFile(path.join(__dirname, '../build/index.html'));
})

app.use(async (req, res, next) => {
    const { authtoken } = req.headers;

    if (authtoken) {
        try {
            req.user = await admin.auth().verifyIdToken(authtoken);
        } catch (e) {
            return res.sendStatus(400);
        }
    }

    req.user = req.user || {};

    next();
});

app.get('/api/articles/:name', async (req, res) => {
    const { name } = req.params;
    const { uid } = req.user;

    const article = await db.collection('articles').findOne({ name });

    if (article) {
        const upvoteIds = article.upvoteIds || [];
        article.canUpvote = uid && !upvoteIds.includes(uid);
        res.json(article);
    } else {
        res.sendStatus(404);
    }
});

app.use((req, res, next) => {
    if (req.user) {
        next();
    } else {
        res.sendStatus(401);
    }
});

app.put('/api/articles/:name/upvote', async (req, res) => {
    const { name } = req.params;
    const { uid } = req.user;

    const article = await db.collection('articles').findOne({ name });

    if (article) {
        const upvoteIds = article.upvoteIds || [];
        const canUpvote = uid && !upvoteIds.includes(uid);

        if (canUpvote) {
            await db.collection('articles').updateOne({ name }, {
                $inc: { upvotes: 1 },
                $push: { upvoteIds: uid },
            });
        }

        const updatedArticle = await db.collection('articles').findOne({ name });
        res.json(updatedArticle);
    } else {
        res.send('That article doesn\'t exist');
    }
});

app.post('/api/articles/:name/comments', async (req, res) => {
    const { name } = req.params;
    const { text } = req.body;
    const { email } = req.user;

    await db.collection('articles').updateOne({ name }, {
        $push: { comments: { postedBy: email, text } },
    });
    const article = await db.collection('articles').findOne({ name });

    if (article) {
        res.json(article);
    } else {
        res.send('That article doesn\'t exist!');
    }
});

const PORT = process.env.PORT || 8000;

connectToDb(() => {
    console.log('Successfully connected to database!');
    app.listen(PORT, () => {
        console.log('Server is listening on port ' + PORT);
    });
})

 

그리고 이제 데이터베이스 연결설정을 해준 db.js파일에서 connection 정보를 변경해줍니다.

connection정보는 위에 MongoDB atlas에서 이전에 생성한 connection 정보를 이용합니다.

변경된 db.js파일은 다음과 같습니다.

db.js

import { MongoClient } from 'mongodb';

let db;

async function connectToDb(cb) {
    const client = new MongoClient(`mongodb+srv://${process.env.MONGO_USERNAME}:${process.env.MONGO_PASSWORD}@blogdb.nfcxvxc.mongodb.net/?retryWrites=true&w=majority&appName=BlogDB`);
    await client.connect();
    db = client.db('react-blog-db');
    cb();
}

export {
    db,
    connectToDb,
};

Express node에서 데이터베이스 접속을 위한 설정은 다 되었습니다. 이제 블로그에서 사용가능하게 하기 위해 초기 데이터베이스 설정을 MongoDB shell을 통해서 해주겠습니다.

터미널에서 MongoDB shell로 접속을 합니다. 접속 스트링은 Atlas의 connection을 mongodb shell 정보를 확인하면 됩니다.

위의 연결 스트링을 카피한후 터미널에 붙여넣기 하여 데이터베이스에 연결을 합니다. 그리고 비밀번호를 입력후에 접속을 합니다.

데이터베이스를 변경하기 위해 use react-blog-db 명령어로 데이터베이스 사용을 지정합니다.

이제 블로그의 초기화 데이터 값을 아래와 같이 저장합니다.

db.articles.insertMany([{
	name: 'learn-react',
    upvotes: 0,
    comments: [],
}, {   
	name: 'learn-node',
    upvotes: 0,
    comments: [],
}, {    
	name: 'mongodb',
    upvotes: 0,
    comments: [],
}])

 

데이터베이스에 기본 데이터가 저장 되었습니다.

MongoDB shell에서 Ctrl + c 버튼 두번으로 나온다음 서버를 npm run dev를 실행시켜 확인합니다.

위에 메세지에서 데이터베이스 연결이 성공되었다고 나오는지 확인합니다. 

그리고 블로그 페이지도 확인합니다.

모든 설정이 초기화 되어 있고 댓글과 좋아요도 초기값으로 되어 있는것을 확인할수 있습니다.

 

이제 우리는 원격으로 데이터베이스 접속을 할수 있도록 블로그 앱을 변경시켰습니다!

반응형