프로젝트 환경 구축하기
아래 명령어를 통해 package.json 파일을 서버 디렉터리에 생성한다.
> npm init --y
타입스크립트를 개발 언어로 하는 Node.js 프로젝트는 항상 다음 3개의 패키지를 설치해 줘야한다. @types/node 패키지는 setTimeout과 같은 자바스크립트 엔진이 제공하는 기능을 타입 스크립트에서 사용할 때 필요한 타입 라이브러리이다.
> npm i -D typescript ts-node @types/node
다음으로는 tsconfig.json 설정 파일을 생성한다.
> tsc -- init
타입스크립트 언어로 몽고DB를 사용하려면 mongodb라는 이름의 드라이버 패키지를 설치해야 한다.
> npm i mongodb
> npm i -D @types/mongodb
위와 같이 설치를 진행했을 경우 package.json의 내용은 아래와 같다.
{
"name": "ch07_2_server",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"description": "",
"devDependencies": {
"@types/mongodb": "^4.0.6",
"@types/node": "^22.10.4",
"ts-node": "^10.9.2",
"typescript": "^5.7.2"
},
"dependencies": {
"mongodb": "^6.12.0"
}
}
개발환경이 정상적으로 갖춰졌는지 src/index.ts를 생성해 실행해보자.
console.log('Hello world')
생성한 index.js를 실행한다.
> ts-node src/index.js
Hello world
몽고DB와 연결하기
프로그래밍으로 "mongodb://localhost:27017" URL 사용 시 몽고DB와 연결할 수 있다. mongodb는 프로토콜 이름이고 localhost는 호스트이름, 기본 포트는 27017이다.
mongodb 패키지는 몽고DB와 연결하기 위한 MongoClient 클래스를 제공하며 해당 클래스는 connect 정적 메서드를 제공해 반환값은 프로미스 형태로 MongoClient를 얻는다.
import {MongoClient} from 'mongodb'
static connect(url: string): Promise<MongoClient>
몽고 DB 관련 유틸리티 함수를 만들기 위해 mongodb 디렉터리를 생성해 connectAndUseDB를 추가하자.
- MongoClient : MongoDB 서버에 연결하는 주요 클래스이다. 이 객체를 통해 MongoDB 인스턴스에 연결을 생성한다.
- Db : MongoDB 데이터베이스를 나타내는 클래스이다. 연결 후 특정 데이터베이스를 참조하기 위해 사용한다.
import { MongoClient, Db } from "mongodb";
export type MongoDB = Db;
export type ConnectCallback = (db: MongoDB) => void;
export const connectAndUseDB = async (
callback: ConnectCallback,
dbName: string,
mongoUrl: string = "mongodb://localhost:27017"
) => {
let connection;
try {
connection = await MongoClient.connect(mongoUrl); // 몽고DB에 연결
const db: Db = connection.db(dbName); // 몽고쉘의 'use dbName'과 동일
callback(db); // db 객체를 콜백 함수의 매개변수로 호출
} catch (e) {
if (e instanceof Error) console.log(e.message);
}
};
생성된 connectAndUseDB 컴포넌트를 connectTest.ts 파일을 추가해 몽고DB가 정상적으로 연결되는지 확인하기 위해 파일을 추가한다.
import * as M from "../mongodb";
const connectDB = (db: M.MongoDB) => {
console.log("db", db);
};
const connectTest = () => {
M.connectAndUseDB(connectDB, "ch07");
};
connectTest(); // 연결 테스트 수행
추가된 파일을 터미널을 통해 실행해보자. 몽고DB가 응답해 실행 결과를 출력하므로 연결이 정상적으로 수행된 것을 확인할 수 있다.
> ts-node connectTest.ts
db Db {
s: {
options: {
enableUtf8Validation: true,
forceServerObjectId: false,
pkFactory: [Object],
raw: false,
readPreference: [ReadPreference],
retryWrites: true
},
...(생략)...
컬렉션의 CRUD 메서드
몽고 쉘에서는 'db.컬렉션_이름' 형태로 컬렉션에 접근할 수 있었고 프로그래밍에서는 'db.collection(컬렉션_이름)' 과 같은 형태로 접근할 수 있다.
문서 생성 메서드 사용하기
user 컬렉션에 insertOne과 insertMany 메서드를 사용해 데이터를 입력해보자. 다음은 두 메서드의 타입 선언문으로 둘 모두 프로미스 객체를 반환함을 알 수 있다.
insertOne(doc: OptionalUnlessRequiredId<TSchema>): Promise<InsertOneResult<TSchema>>
insertMany(doc: OptionalUnlessRequiredId<TSchema>[]): Promise<InsertManyResult<TSchema>>
이 메서드를 통해 문서를 추가하기 위해 insertTest.ts 파일에 코드를 추가하자.
import * as M from "../mongodb";
const connectCB = async (db: M.MongoDB) => {
try {
const user = db.collection("user");
try {
await user.drop();
} catch (error) {}
const jack = await user.insertOne({ name: "Jack", age: 32 });
console.log("jack", jack);
const janeAndTom = await user.insertMany([
{ name: "Jane", age: 22 },
{ name: "Tom", age: 11 },
]);
console.log("janeAndTom", janeAndTom);
} catch (e) {
if (e instanceof Error) console.log(e.message);
}
};
const insertTest = () => {
M.connectAndUseDB(connectCB, "ch07");
};
insertTest();
실행결과도 몽고셸의 실행결과와 일치하는 것을 확인할 수 있다.
> ts-node insertTest.ts
jack {
acknowledged: true,
insertedId: new ObjectId('67778b9c1bcd4c334ac5a73d')
}
janeAndTom {
acknowledged: true,
insertedCount: 2,
insertedIds: {
'0': new ObjectId('67778b9c1bcd4c334ac5a73e'),
'1': new ObjectId('67778b9c1bcd4c334ac5a73f')
}
}
문서 검색 메서드 사용하기
findOne, find 메서드의 타입 선언문 프로미스 객체를 반환하는 findOne과 달리 find는 FindCursor 타입 객체를 반환한다.
findOne(filter: Filter<TSchema>): Promise<WithId<TSchema> | null>
find(filter: Filter<TSchema>, options?: FindOptions): FindCursor<withId<TSchema>>
FindCursor 타입 객체는 toArray란 메서드를 제공하며 find의 반환값을 자바스크립트 배열로 바꿔준다.
const cursor = await find({})
const arrayResult = cursor.toArray()
문서 검색을 테스트 하기 위해 findTest.ts 파일을 추가해 작성 후 실행해보자.
import * as M from "../mongodb";
const connectCB = async (db: M.MongoDB) => {
try {
const user = db.collection("user");
const one = await user.findOne({});
console.log("one", one);
const many = await user.find({}).toArray();
console.log("many", many);
} catch (e) {
if (e instanceof Error) console.log(e.message);
}
};
const findTest = () => { M.connectAndUseDB(connectCB, "ch07"); };
findTest();
findTest.ts 파일의 실행결과로 앞서 'user' 컬렉션에 삽입한 내용이 검색된 것을 확인할 수 있다.
> ts-node findTest.ts
one {
_id: new ObjectId('67778b9c1bcd4c334ac5a73d'),
name: 'Jack',
age: 32
}
many [
{
_id: new ObjectId('67778b9c1bcd4c334ac5a73d'),
name: 'Jack',
age: 32
},
{
_id: new ObjectId('67778b9c1bcd4c334ac5a73e'),
name: 'Jane',
age: 22
},
{
_id: new ObjectId('67778b9c1bcd4c334ac5a73f'),
name: 'Tom',
age: 11
}
]
문서 수정 메서드 사용하기
아래 선언문은 컬렉션의 문서 수정 관련 메서드들의 타입 선언문으로 모두 프로미스 객체를 반환하는 걸 알 수 있다.
updateOne(filter:Filter<TSchema>, update:Updatefilter<TSchema>|Partial<TSchema>):
Promise<UpdateResult>;
udpateMany(filter: Filter<TSchema>, update:Updatefilter<TScema>): Promise<UpdateResult | Document>;
findOneAndUpdate(filter:Filter<TSchema>, update:updateFilter<TSchema>, options: FindOneAndUpdateOptions):
Promise<ModifyResult<TSchema>>;
findOneAndUpdate 메서드를 호출 시 몽고셸은 returnNewDocument 속성 값을 true로 했지만, 프로그래밍에서는 returnDocument 속성 값을 'after'로 설정해야 한다.
const findOneResult = await.user.findOneAndUpdate(
{name: 'John'},
{$set: {age: 66}},
{returnDocument: 'after'} // before or after
);
문서 수정 메서드를 테스트 하기 위해 updateTest.ts 파일을 추가해 내용을 입력한다.
import * as M from "../mongodb";
const connectCB = async (db: M.MongoDB) => {
try {
const user = db.collection("user");
await user.updateOne(
{ name: { $regex: /^J.*$/ } },
{ $set: { name: "John" }, $inc: { age: 10 } }
);
const updateOneResult = await user.find({}).toArray();
console.log("updateOneResult", updateOneResult);
await user.updateMany({ name: { $regex: /^J.*$/ } }, { $inc: { age: 10 } });
const updateManyResult = await user.find({}).toArray();
console.log("updateManyResult", updateManyResult);
const findOneResult = await user.findOneAndUpdate(
{ name: "John" },
{ $set: { age: 66 } },
{ returnDocument: "after" }
);
console.log("findOneResult", findOneResult);
} catch (e) {
if (e instanceof Error) console.log(e.message);
}
};
const updateTest = () => {
M.connectAndUseDB(connectCB, "ch07");
};
updateTest();
실행결과로 몽고셸에서 봤더 내용과 일치함을 확인할 수 있다.
> ts-node updateTest.ts
updateOneResult [
{
_id: new ObjectId('67778b9c1bcd4c334ac5a73d'),
name: 'John',
age: 42
},
{
_id: new ObjectId('67778b9c1bcd4c334ac5a73e'),
name: 'Jane',
age: 22
},
{
_id: new ObjectId('67778b9c1bcd4c334ac5a73f'),
name: 'Tom',
age: 11
}
]
updateManyResult [
{
_id: new ObjectId('67778b9c1bcd4c334ac5a73d'),
name: 'John',
age: 52
},
{
_id: new ObjectId('67778b9c1bcd4c334ac5a73e'),
name: 'Jane',
age: 32
},
{
_id: new ObjectId('67778b9c1bcd4c334ac5a73f'),
name: 'Tom',
age: 11
}
]
findOneResult {
_id: new ObjectId('67778b9c1bcd4c334ac5a73d'),
name: 'John',
age: 66
}
문서 삭제 메서드 사용하기
다음은 컬렉션의 deleteOne과 deleteMany 메서드의 타입 선언문으로 두 메서드는 모두 프로미스 객체를 반환한다.
deleteOne(filter: Filter<TSchema>): Promise<DeleteResult>;
deleteMany(filter: Filter<TSchema>): Promise<DeleteResult>;
문서 삭제를 테스트하기 위해 deleteTest.ts 파일을 추가해 내용을 넣고 실행해보자.
import * as M from "../mongodb";
const connectCB = async (db: M.MongoDB) => {
try {
const user = db.collection("user");
const deleteOneResult = await user.deleteOne({ name: { $regex: /^J.*$/ } });
console.log("deleteOneResult", deleteOneResult);
const deleteManyResult = await user.deleteMany({
name: { $regex: /^J.*$/ },
});
console.log("deleteManyResult", deleteManyResult);
const userDocuments = await user.find({}).toArray();
console.log("userDocuments", userDocuments);
} catch (e) {
if (e instanceof Error) console.log(e.message);
}
};
const deleteTest = () => {
M.connectAndUseDB(connectCB, "ch07");
};
deleteTest();
실행결과 또한 앞서 본 몽고셸의 결과와 일치하는걸 확인할 수 있다.
> ts-node deleteTest.ts
deleteOneResult { acknowledged: true, deletedCount: 1 }
deleteManyResult { acknowledged: true, deletedCount: 1 }
userDocuments [
{
_id: new ObjectId('67778b9c1bcd4c334ac5a73f'),
name: 'Tom',
age: 11
}
]
'FrontEnd > React' 카테고리의 다른 글
[React] JSON 웹 토큰으로 회원 인증 구현하기 (0) | 2025.01.07 |
---|---|
[React] 익스프레스 프레임워크로 API 서버 만들기 (0) | 2025.01.06 |
[React] 공개 라우트와 비공개 라우트 구현하기 (2) | 2024.12.30 |
[React] Outlet 컴포넌트와 중첩 라우팅 (0) | 2024.12.27 |
[React] 처음 만나는 리액트 라우터 (1) | 2024.12.27 |