JavaScript/JS백엔드

MongoDB 사용하기

염두리안 2025. 1. 1. 15:11
728x90
반응형
  • 스키마 정의하기
    • 스키마: 데이터의 틀
import mongoose from "mongoose";

const TaskSchema = new mongoose.Schema(
    {
        titile: {
            type: String,
        },
        description: {
            type: String,
        },
        siComplete: {
            type: Boolean,
            default: false,
        },
    },
    {
    // timestamps 사용시 mongo가 알아서 create, update app 필드를 생성&관리함 
        timestamps: true,
    }
);

// 첫번째 아규먼트는 첫 글자를 대문자&단수형으로 씀
const Task = mongoose.model('Task', TaskSchema); // tasks 컬랙션에 데이터 추가, 조회, 삭제

export default Task;
  • 시드 데이터 넣기
import mongoose from "mongoose";
import data from './mock.js';
import Task from '../models/Task.js';
import { DATABASE_URL } from "../env.js";

// 데이터베이스에 연결하는 코드
mongoose.connect(DATABASE_URL);

await Task.deleteMany({}); // 삭제 조건을 파라미터로 받음
await Task.insertMany(data); // 삽입할 데이터를 파라미터로 받음

mongoose.connection.close(); // 연결 종료
  • 데이터 조회하기
    • Model.find() 메소드에 필터 객체 전달시 조건을 만족하는 데이터만 조회 가능
    • 비교연산자
      • $gt : 특정 값을 초과하는지 확인 | Person.find({ age: { $gt: 35 } });
      • $lt : 특정 값 미만인지 확인 | Person.find({ age: { $lt: 35 } });
    • Regex 연산자: 문자열 필드가 특정 패턴을 가지고 있는지 확인
      • $regex | Person.find({ email: { $regex: 'gmail\.com$' } });
    • AND 연산자: 하나의 객체 안에 여러 조건 작성하면 됨
      • Person.find({ age: { $lt: 32 }, email: { $regex: 'gmail\.com$' } });
    • OR 연산자: $or
      • Person.find({ $or: [{ age: { $lt: 32 } }, { email: { $regex: 'gmail\.com$' } }] });
    • .findOne() : 다른 조건을 만족하는 객체 하나를 가져오고 싶을 때 사용... 조건을 만족하는 객체가 여러 개일 경우, 처음으로 매쳉된 객체 하나만 리턴
      • Person.findOne({ name: 'James' });
    • 모델 메소드 공식문서
    • 쿼리 메소드 공식문서
// app.js에 있던 코드를
app.get('/tasks/:id', (req, res) => {
    const id = Number(req.params.id);
    const task = mocktasks.find((task) => task.id === id);
    if (task){
        res.send(task);
    } else {
        res.status(404).send({ message: `Can't find given id.` });
    }
});

// 데이터베이스를 사용하도록 변경(쿼리를 리턴)
app.get('/tasks/:id', async (req, res) => {
    const id = req.params.id;
    const task = await Task.findById(id);
    if (task){
        res.send(task);
    } else {
        res.status(404).send({ message: `Can't find given id.` });
    }
});
// app.get('/tasks') 함수를 다음과 같이 변경
app.get('/tasks', async (req, res) => {
    const sort = req.query.sort;
    const count = Number(req.query.count);
    
    const sortOption = { 
        createdAt: sort === 'oldest' ? 'asc' : 'desc'
    };
    const tasks = await Task.find().sort(sortOption).limit(count); // 여러 객체를 가져옴

    res.send(newTasks);
});
  • 데이터 생성과 유효성 검사
    • MongoDB에선 스키마를 통해 유효성 검사 가능
// [데이터생성] app.js 에 app.post를 다음과 같이 수정
app.post('/tasks', async (req, res) => {
    const newTasks = await Task.create(req.body);
    res.status(201).send(newTasks);
});
  • 비동기 코드 오류 처리하기
function asyncHandler(handler) {
    return async function (req, res) {
        try{
            await handler(req, res);
        } catch (e) {
            if (e.name === 'ValidationError') {
                res.status(400).send({ message: e.message });
            } else if (e.name === 'CastError') {
                res.status(404).send({ message: 'Cannot find given id.'});
            } else {
                res.status(500).send( {message: e.message });
            }
        }
    }
}
  • 데이터 수정/삭제
// patch, delete 함수를 다음과 같이 수정
app.patch('/tasks/:id', async (req, res) => {
    const id = req.params.id;
    const task = await Task.findById(id);
    if (task){
        Object.keys(req.body).forEach((key) => {
            task[key] = req.body[key];
        });
        await task.save();
        res.send(task);
    } else {
        res.status(404).send({ message: `Can't find given id.` });
    }
});

app.delete('/tasks/:id', asyncHandler(async (req, res) => {
    const id = req.params.id;
    const task = await Task.findByIdAndDelete(id);
    if (task){
        res.sendStatus(204);
    } else {
        res.status(404).send({ message: `Can't find given id.` });
    }
}));

  • MongoDB 접속시 Mongoose 라이브러리 사용
// DB접속
import mongoose from 'mongoose';
mongoose.connect('mongodb+srv://...');
// 스키마와 모델
import mongoose from 'mongoose';

const TaskSchema = new mongoose.Schema(
  {
    title: {
      type: String,
      required: true,
      maxLength: 30,
    },
    description: {
      type: String,
    },
    isComplete: {
      type: Boolean,
      required: true,
      default: false,
    },
  },
  {
    timestamps: true,
  }
);

const Task = mongoose.model('Task', TaskSchema);

export default Task;

// 유효성 검사를 원한다면...
{
  title: {
    type: String,
    required: true,
    maxLength: 30,
    validate: {
       validator: function (title) {
         return title.split(' ').length > 1;
       },
       message: 'Must contain at least 2 words.',
     },
  },
  // ...
}
  • CRUD 연산
// 생성(create)
app.post('/tasks', async (req, res) => {
  const newTask = await Task.create(req.body); // .create()로 객체 생성
  res.status(201).send(newTask);
});
// 조회(read)
app.get('/tasks', async (req, res) => {
  const tasks = await Task.find(); // 여러 객체 조회시 .find() 사용
  res.send(tasks);
});
// id로 특정 객체 조회시 .findById() 사용
app.get('/tasks/:id', async (req, res) => {
  const task = await Task.findById(req.params.id);
  res.send(task);
  } else {
    res.status(404).send({ message: 'Cannot find given id.' });
  }
});

// 정렬, 개수 제한
// find는 쿼리 리턴... 메소드 체이닝 가능
app.get('/tasks', async (req, res) => {
    /** 쿼리 파라미터
     *  - sort: 'oldest'인 경우 오래된 태스크 기준, 나머지 경우 새로운 태스크 기준
     *  - count: 태스크 개수
     */
    const sort = req.query.sort;
    const count = Number(req.query.count) || 0;

    const sortOption = { createdAt: sort === 'oldest' ? 'asc' : 'desc' };
    const tasks = await Task.find().sort(sortOption).limit(count);

    res.send(tasks);
  })
);
// 수정(update)
app.patch('/tasks/:id', async (req, res) => {
  const task = await Task.findById(req.params.id);
  if (task) {
    Object.keys(req.body).forEach((key) => {
      task[key] = req.body[key];
    });
    await task.save();
    res.send(task);
  } else {
    res.status(404).send({ message: 'Cannot find given id.' });
  }
});
// 삭제(delete)
app.delete('/tasks/:id', async (req, res) => {
  const task = await Task.findByIdAndDelete(req.params.id);
  if (task) {
    res.sendStatus(204);
  } else {
    res.status(404).send({ message: 'Cannot find given id.' });
  }
});
  • 비동기 오류
function asyncHandler(handler) {
  return async function (req, res) {
    try {
      await handler(req, res);
    } catch (e) {
      // e.name(오류 이름), e.message(오류 메시지) 이용해서 오류 처리
    }
  };
}

// ...

app.get('/tasks', asyncHandler(async (req, res) => { ... }));
728x90
반응형