이번 시간엔 Next.js에서 데이터베이스를 연결하는 방법에 대해 다루어볼 예정이다. 데이터베이스는 그중에서도 비관계형 데이터베이스
인 MongoDB
를 사용하여 진행할 예정이다.
아래 링크를 타고 들어가서 회원가입이 되지 않았더라면 회원가입을 진행해준다.
그 이후에 이런걸 선택하라고 할텐데.. 우선 우리는 체험하고 공부하는데 의의가 있으니 무료 버전과 AWS를 선택해준다.
그 아래에 있는 지역은 자신이 가장 가까이 있는 곳으로 해주는 곳으로 해야 빠르게 접근할 수 있다.
SECURITY -> Database Access
에 들어가면 DB 접속용 아이디 비번을 생성할 수 있는데, 자신이 기억할 수 있는 아이디와 비번으로 만들자.
여기서 주의점은 Built-in Role
영역을 Atlas admin
설정 해주어야 한다. 이를 해야 모든 권한을 부여 받을 수 있다.
데이터베이스에 접근할 때, IP를 미리 정의해놓는 일종의 보안장치를 설정하는 과정이다.
SECURITY -> Network Access
에 접속 후에 IP 주소를 입력해주면 된다. 만약 본인이 모든 IP 주소를 설정해주고 싶다면 ALLOW ACCESS FROM ANYWHERE 을 클릭하면 0.0.0.0/0 이라는 주소로 설정해줄 수 있다. 이는 모든 IP주소를 허락해주는 점이다.
만약 본인의 프로젝트의 보안성을 신경쓴다면 모든 IP주소를 허용해주는 것이 아니라, 특정 IP주소를 허용해주는 편이 좋을 것 같다.
이제 Next.js에서 사용할 수 있게 되었는데, 이를 연결할 데이터베이스 주소가 존재한다. 이는 어딨는지 미리 확인하자.
- DEPLOYMENT
- Database
- 본인 데이터베이스 프로젝트 이름 클릭
- Connect
- Connect to your application ->
- Add your connection string into your application code
아래 순서로 타고 들어가면 사용할 수 있는 주소를 확인할 수 있다. 이는 나중에 데이터베이스를 사용할때 코드에서 사용하니 복사해두자.
우선, MongoDB를 사용할때마다 데이터베이스를 불러오는 코드는 프로그램의 부담을 줄 수 있으니, 파일을 따로 만들어두자.
import { MongoClient } from 'mongodb'
const url = '본인이 만든 데이터베이스 주소 링크'
const options = { useNewUrlParser: true }
let connectDB
if (process.env.NODE_ENV === 'development') {
if (!global._mongo) {
global._mongo = new MongoClient(url, options).connect()
}
connectDB = global._mongo
} else {
connectDB = new MongoClient(url, options).connect()
}
export { connectDB }
이렇게 만들어두고 필요할때마다 connectDB변수를 import해와서 관련 기능을 사용하자.
이제 MongoDB에 있는 데이터를 불러와보자.
만약 데이터를 이렇게 생성해놨다고 가정하고 이를 불러와보자.
const client = await connectDB;
const db = client.db("forum")
let result = await db.collection('post').find().toArray();
이 코드를 추가하면 result에 값을 가져와줄 수 있다.
코드 설명을 하자면 client.db("데이터베이스 명")
을 설정해주고, db.collection('콜렉션 명')
을 설정해준다.
보통 이것은 데이터베이스에서 뭐를 검색하고, 삽입하고, 삭제하던 다 동일하다.
이후에 탐색을 할때는 find
라는 함수를 사용한다. 이를 이용하면 모든 값을 불러온다. 그리고 .toArray()라는 함수를 통해 배열의 형태로 받아와준다.
추가적인 코드 설명을 하자면 await
는 무엇이란 말인가?
보통 자바스크립트는 오래 걸리는 코드가 있을시, 이를 건너뛰고 다음 코드를 실행한다. 이 때문에 데이터베이스를 데이터를 불러올때 시간이 오래걸려 데이터를 받지 않은 상태로 다음 코드로 넘어갈 수 있다.
이를 방지하기 위한 문법이다.
await
를 추가하면 오래 걸리더라도 그 코드를 완료하고 넘어간다.
주의 사항이 하나 있는데, 이를 사용하기 위해서는 함수에 async
를 붙어줘야 사용할 수 있다.
그러면 이 데이터를 가지고 한번 컴포넌트를 구성하면 데이터베이스의 값이 잘 나올까?
잘 나오는 것을 확인할 수 있다.
그렇다면 데이터를 삽입하는 코드를 짜보자.
우선 유저가 관련 데이터를 입력할 수 있는 컴포넌트를 만들어야 할 것이다.
이 컴포넌트 만드는 법은 자유겠지만.. 우선 본인은 다음과 같이 구성했다.
export default function Write(){
return(<>
<div className="p-20">
<h4>글 작성</h4>
<form action="/api/post/write" method="POST">
<input name="title" placeholder="글 제목을 입력해주세요."></input>
<input name="content"placeholder="글 내용을 입력해주세요."></input>
<button type="submit">버튼</button>
</form>
</div>
</>)
}
input태그로 값을 받은 후, POST
방법으로 /api/post/write
이것을 실행시켜줬다.
그러면 이 값을 받아서 어떻게 추가하는지 /api/post/write
이 놈의 코드를 한번 봐보자.
import {connectDB} from "/util/database"
const Write = async(request,answer) =>{
const client = await connectDB;
const db = client.db("forum")
let result = await db.collection('post').insertOne(request.body);
answer.redirect(300, '/list')
}
export default Write;
위에 코드는 동일하고, find
함수 대신 insertOne
이라는 함수를 사용한다.
이 함수의 인자에는 넣을 데이터의 형태를 넣어준다. 예시 데이터를 봐보자.
이 데이터를 보면 _id는 우리가 지정해주지 않는 고유값이고, title과 content를 넣어서 보내주면 된다.
그런데 위의 코드를 보면 request.body를 보내준다.
request.body에는 입력 컴포넌트이 입력된 값들이 담겨져있다. 어떻게 담겨져 있을까?
{ name1 : 입력 값, name2 : 입력 값 }
이런식으로 값이 저장되어있다. 그래서 값을 그냥 넣어도 된다.
저렇게 말고
insertOne({title: request.body.title, content: request.body.content})
로 입력해주어도 똑같은 기능을 한다.
데이터 수정은 입력이랑 비슷한데, 함수만 조금 다르다.
우선 코드를 먼저 보면서 살펴보자.
import {connectDB} from "/util/database"
import { ObjectId } from "mongodb";
const ModifyFun = async(request,answer) =>{
// 수정할 문서의 조건
const filter = { _id: new ObjectId(request.body.id) };
const client = await connectDB;
const db = client.db("forum")
// 데이터 저장
let result = await db.collection('post').updateOne(filter,{$set : {title: request.body.title, content:request.body.content}});
answer.redirect(302, '/list')
}
export default ModifyFun;
사실 가장 큰 특징은 filter 조건이 필요하다는 점이다.
데이터 수정 시에 가장 많이 쓰는 함수가 updateOne
인데 이 함수의 형태는 다음과 같다.
updateOne(조건, {$set: 바꿀 데이터}
여기서 조건은 어떤 조건의 값을 바꿀 것인지에 대한 값이다.
위의 코드는 사용자 입력 컴포넌트에서 보내준 id를 받아서 그 id에 해당하는 값을 받아온 값으로 수정하는 코드를 짠 것이다.
이제 약간씩 느낌이 올것이다. 아 수정할때는 어떤 데이터
를 수정할 것인지에 대한 조건
이 필요하구나.
그러면 삭제할땐 뭐가 필요할까?
똑같이 어떤 데이터
를 삭제할 것인지에 대한 조건
이 필요하겠다고 생각이 든다.
이 생각을 가지고 코드를 봐보자.
import {connectDB} from "/util/database"
import { ObjectId } from "mongodb";
const Delete = async(request,answer) =>{
const filter = { _id: new ObjectId(JSON.parse(request.body).id) }; // 수정할 문서의 조건
const client = await connectDB;
const db = client.db("forum")
// 데이터 저장
let result = await db.collection('post').deleteOne(filter);
answer.status(200).json("삭제완료");
}
export default Delete;
이제는 설명을 안해도 될 것 같은 느낌이 든다...
하지만 그래도 간단히 설명해보자면, 이번엔 deleteOne
이라는 함수를 사용한다. 이 함수는 안에 우리가 예상한대로 어떤 값을 삭제할지에 대한 조건을 넣어서 보내준다.
위에서는 MongoDB를 활용하기 위한 기본 객체 생성 코드를 보았고, 그 객체를 활용하고 데이터베이스의 값을 탐색, 수정, 삭제 하는 방법에 대해 배웠다.
보면서 느꼈을 수도 있지만 본인이 블로깅을 할 때 탐색, 수정, 삭제를 하는 함수에 대한 함수는 최대한 간략하게 하였다. 이 이유는 이 함수는 본인이 설명한 것 말고도 상황에 맞는 함수들이 매우 많고 이는 상황에 따라 검색하여 어떻게 사용하는지 공식문서를 참고하는 것이 매우 좋다.
위의 코드는 예외처리도 안된 가장 간단한 코드이기 때문에 흐름 정도를 보는 정도로 봤으면 좋겠다. 이를 통해 배운 흐름을 가지고 프로젝트 때 필요한 함수를 통해 데이터베이스를 다루는 능력.. 을 기르는 것이 가장 중요하게 생각이 든다.
글 잘 봤습니다.