Menu

Node.js에서 MongoDB 사용하기: find, insert, update 예제

공식 mongodb 드라이버로 Node.js에서 MongoDB를 씁니다. MongoClient로 연결한 뒤 컬렉션의 문서를 추가, 조회, 수정, 삭제하며, 모두 async/await로 작성합니다.

이 페이지에는 실행 가능한 에디터가 있습니다. 편집하고 실행하면 결과를 바로 볼 수 있습니다.

Node.js에서 MongoDB를 쓰려면 공식 드라이버를 설치하고(npm install mongodb), new MongoClient(uri)로 연결한 뒤, client.db('name')로 데이터베이스를, db.collection('name')으로 컬렉션을 고릅니다. 모든 작업(insertOne, find, updateOne, deleteOne)이 Promise를 반환하므로 await합니다. 문서는 일반 자바스크립트 객체로 들어가고 나옵니다.

[ 'Dune', 'Neuromancer', 'Hyperion' ]이 출력됩니다. shop 데이터베이스와 books 컬렉션은 그전에는 없었습니다. MongoDB가 첫 삽입 때 만들었고, toArray()는 find() 커서가 가리키는 모든 문서를 불러옵니다.

필터와 projection으로 문서 찾기

필터는 원하는 문서를 설명하는 객체입니다. 일반 값은 정확히 일치해야 하고, $gt, $lt, $in, $regex 같은 연산자는 중첩 객체에 씁니다. 두 번째 인자의 projection은 돌려받을 필드를 고릅니다.

recent에는 1960년 이후의 최신 책 두 권, Hyperion과 Neuromancer가 이 순서로 title과 year만 담겨 있습니다. findOne은 처음 일치한 것(또는 null)을 반환하고, countDocuments는 가격이 10 이상인 책을 2권으로 셉니다. $gt: 1960을 $gt: 1985로 바꾸면 Hyperion만 남습니다.

수정과 삭제

updateOne(filter, update)은 처음 일치한 문서를 바꿉니다. 수정에는 연산자를 씁니다. $set은 필드를 교체하고, $inc는 숫자에 더하고, $unset은 필드를 지우고, $push는 배열에 추가합니다. updateMany와 deleteMany는 일치하는 모든 문서에 적용됩니다.

수정은 문서 하나와 일치해 그것을 바꿨으므로 Dune은 이제 가격이 10, 재고가 2이고, 재고가 없는 책을 지우면 1권이 남습니다. 수정에는 연산자가 반드시 필요합니다. $set 없이 { price: 10 }을 넘기면 드라이버가 거부합니다(문서 전체를 교체하는 호출은 replaceOne입니다).

ObjectId와 인덱스

모든 문서에는 _id가 있습니다. 직접 지정하지 않으면 드라이버가 ObjectId를 만듭니다. 문자열로 들어온 id(예를 들어 URL에서)로 문서를 찾으려면 new ObjectId(id)로 감싸세요. 인덱스는 필드 검색을 빠르게 하고, 유니크 인덱스는 MongoDB가 중복을 거부하게 합니다.

ObjectId는 문자열로 바꾸면 16진수 24자이고, 일반 문자열로 검색하면 아무것도 찾지 못하므로 그 줄은 null을 출력합니다. 두 번째 삽입은 유니크 인덱스를 어겨 코드 11000으로 실패합니다. "이미 사용 중인 이메일"은 이렇게 감지합니다.

Express API에서 MongoDB 쓰기

서버가 시작될 때 한 번 연결하고 컬렉션을 공유하세요. 요청마다 새 연결을 열지 마세요. 드라이버는 연결 풀을 두고 재사용합니다.

GET /books는 두 권을 모두 반환하고, 각각 _id가 있습니다. id 하나를 복사해 GET /books/<id>에 넣으면 한 권을 가져오고, {"title": "Foundation", "year": 1951} 같은 JSON 본문으로 POST /books를 보낸 뒤 다시 목록을 볼 수도 있습니다.

실제 앱은 연결 문자열을 코드에 쓰지 않고 process.env.MONGODB_URI에서 읽습니다.

드라이버 위에 스키마와 검증이 필요하다면 Mongoose(npm install mongoose)가 드라이버를 감싸 줍니다.

const Book = mongoose.model('Book', new mongoose.Schema({ title: String, year: Number }));
await Book.create({ title: 'Dune', year: 1965 });

흔한 실수

toArray()를 잊는 것. find()는 문서가 아니라 커서를 반환합니다. 그대로 로그를 찍으면 커서 객체가 보입니다. toArray()를 호출하거나 for await로 순회하세요.

요청마다 연결하는 것. new MongoClient는 각자 자기 풀을 엽니다. 시작할 때 클라이언트를 하나 만들어 어디서나 재사용하세요.

스크립트에서 클라이언트를 닫지 않는 것. 열린 클라이언트는 코드가 끝난 뒤에도 프로세스를 살려 둡니다. 스크립트 끝에서 await client.close()를 호출하세요. 서버는 살아 있는 동안 계속 열어 둡니다.

자주 묻는 질문

mongodb 드라이버와 Mongoose 중 무엇을 써야 하나요?

드라이버는 공식적인 얇은 계층으로, 일반 객체와 MongoDB 자체 쿼리 언어로 작업합니다. Mongoose는 그 위에 스키마, 검증, 모델을 더하므로 모든 문서를 검사하고 싶을 때 도움이 됩니다. 둘 다 같은 데이터베이스와 통신하고, Mongoose는 내부에서 드라이버를 씁니다.

데이터베이스나 컬렉션을 먼저 만들어야 하나요?

아니요. MongoDB는 처음 문서를 넣을 때 둘 다 만듭니다. client.db('shop')과 db.collection('books')는 핸들만 반환합니다.

연결 문자열은 어디에 둬야 하나요?

MONGODB_URI 같은 환경 변수에 두고 process.env.MONGODB_URI로 읽으세요. 호스팅된 데이터베이스의 연결 문자열에는 비밀번호가 들어 있으므로 저장소에 절대 커밋하면 안 됩니다.

id로 검색하면 find가 문서를 반환하지 않는 이유는?

_id는 문자열이 아니라 ObjectId로 저장되므로 { _id: '65f1...' }은 아무것과도 일치하지 않습니다. 먼저 변환하세요. { _id: new ObjectId(id) }입니다.

Coddy 프로그래밍 언어 일러스트

Coddy로 코딩 배우기

시작하기