2-3. 데이터베이스 스키마와 모델
2장의 서론에서는, MongoDB 는 고정적인 스키마를 갖지 않고 있다고 설명을 했습니다. 그런데 이번에 스키마를 미리 만든다니, 조금 헷갈리기도 하지요? 여기서 만드는 스키마는, 데이터베이스 서버측에서 만드는 스키마가 아니라, 우리의 웹서버가 데이터베이스에 들어있는 문서들을 객체화하여 사용 할 수 있도록 스키마를 설정해주는 것 입니다.
데이터베이스의 실제 데이터와, 웹서버의 스키마가 일치하지 않아도, 정상적으로 작동합니다. 단, 만약에 데이터베이스상에선 있는 정보가 서버측의 데이터 스키마에선 설정되어있지 않다면 해당 정보는 undefined
로 보여지게 됩니다.
스키마와 모델
mongoose 에서는 스키마(schema) 와 모델(model) 이라는 개념이 존재하는데 이는 혼동되기 쉽습니다. 스키마는, 해당 컬렉션의 문서에 어떤 종류의 값이 들어가는지를 정의합니다.
다음은, 블로그 포스트 스키마의 예제 코드입니다:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var blogSchema = new Schema({
title: String,
author: String,
body: String,
comments: [{ body: String, date: Date }],
date: { type: Date, default: Date.now },
hidden: Boolean,
meta: {
votes: Number,
favs: Number
}
});
보시면, 문서의 각 항목이 어떤 형식인지 정의가 되어있지요. 포스트의 제목은 문자열 형태이고 덧글은 객체로 이뤄진 배열이고, date 는 날짜형식입니다.
반면, 모델은 스키마를 통해서 만드는 인스턴스입니다.
var Blog = mongoose.model('Blog', blogSchema);
이 객체를 통하여, 데이터베이스에 실제 작업을 할 수 있게 됩니다. 이를 통하여 데이터를 조회하거나, 추가하거나, 수정하거나, 삭제를 할 수 있지요.
스키마 / 모델 만들기
구상하기
우리의 프로젝트를 위한 스키마를 디자인 하기 전에, 연습삼아 우리가 1장에서 만들었던 books API 에서 사용 할 책 관련 데이터 스키마를 준비하고, 모델을 만들어주겠습니다.
책의 정보를 담는 데이터에는 어떤 값들이 필요할까요? 한번 생각을 해봅시다.
- 책 이름
- 저자
- 출판일
- 가격
- 태그
- 데이터 생성날짜
이제, 각 항목들이 어떤 형식으로 이뤄져야 되는지 생각을 해봅시다.
- 책 이름: 책 이름은 문자열 형식이 되겠지요?
- 저자: 연습삼아 저자의 정보가 들어가는곳엔 저자의 이름과 이메일이 들어가도록 설정하겠습니다. 저자가 여러명이 될 수도 있으니, 배열형태로 하도록 하겠습니다.
- 출판일: 날짜가 들어갑니다.
- 가격: 숫자가 들어갑니다.
- 태그: 태그에는 문자열 배열이 들어가도록 설정하겠습니다.
- 데이터 생성날짜: 이 또한 날짜가 들어갑니다. 기본값으로는, 데이터가 만들어지는 서버의 시간을 넣도록 하겠습니다.
자, 그러면 이에 따라 스키마를 만들어보겠습니다.
코드 작성하기
스키마 / 모델에 관련된 코드는, src/models 디렉토리에 작성하도록 하겠습니다. 해당 디렉토리에 book.js 라는 파일을 만들어서 다음과 같이 스키마를 작성해보세요.
src/models/book.js
const mongoose = require('mongoose');
const { Schema } = mongoose;
// Book 에서 사용할 서브다큐먼트의 스키마입니다.
const Author = new Schema({
name: String,
email: String
});
const Book = new Schema({
title: String,
authors: [Author], // 위에서 만든 Author 스키마를 가진 객체들의 배열형태로 설정했습니다.
publishedDate: Date,
price: Number,
tags: [String],
createdAt: { // 기본값을 설정할땐 이렇게 객체로 설정해줍니다
type: Date,
default: Date.now // 기본값은 현재 날짜로 지정합니다.
}
});
// 스키마를 모델로 변환하여, 내보내기 합니다.
module.exports = mongoose.model('Book', Book);
이 파일에선, 두개의 스키마를 만들었습니다. 하나는 저자의 정보가 들어가는 Author 스키마이고, 책의 정보가 들어가는 Book 스키마에서 authors 값의 형식을 지정할때 Author 스키마를 가진 객체들의 배열로 이뤄지도록 설정하였습니다.
그리고, 하단에서는 mongoose.model
을 통하여 우리가 만든 스키마를 모델로 변환하고 다른 파일에서 불러와서 사용 할 수 있도록 내보내주었습니다.
model 함수에선 기본적으론 두개의 파라미터를 필요로합니다. 첫번째는 파라미터는 해당 스키마의 이름이고, 두번째는 스키마 객체입니다. 스키마의 이름을 정해주면, 이의 복수형태로 컬렉션이름을 만들어줍니다.
예를들어, Book 으로 설정한다면, 실제 데이터베이스에서 생성되는 컬렉션 이름은 books 입니다. 그리고, BookInfo 로 설정한다면 bookinfos 로 만들어집니다.
MongoDB 에서 컬렉션 이름을 만들때의 컬렉션은 구분자를 사용하지 않고, (user_info 같은), 복수형태로 쓰는것 (books 처럼)인데요, 만약에 이 컨벤션을 따르고 싶지 않다면 세번째 파라미터로 여러분들이 원하는 이름을 정해주면 됩니다.
예를들자면 다음과 같이 코드를 쓰면 되겠습니다.
mongoose.model('Book', Book, 'custom_book_collection');
모델을 생성하면서 사용한 이름은, 나중에 다른 스키마에서 현재 스키마를 참조해야 할 때 사용됩니다.