🔓데이터베이스/몽고db

mongdb 참조 설계의 두 가지 방식

하얀성 2024. 3. 5. 14:08

1.collection1에서 똑같은 collection인 collection2, collection3 등을 참조

2. collection1에 하부 목록으로 expense, incomes 생성


 

1. users 컬렉션과 별도의  컬렉션 사용

장점

  • 확장성: 대규모 데이터를 다룰 때 더 효율적일 수 있습니다. 각 데이터 유형을 별도의 컬렉션에 저장함으로써, 문서 크기에 대한 걱정 없이 데이터를 추가할 수 있습니다.
  • 유연성: expenses와 incomes 데이터를 독립적으로 관리할 수 있어, 복잡한 쿼리나 데이터 분석이 용이합니다.
  • 성능 최적화: 데이터를 분리함으로써, 특정 작업에 필요한 데이터만 빠르게 조회할 수 있습니다.

단점

  • 조인의 필요성: MongoDB에서는 SQL 데이터베이스의 조인과 같은 기능이 제한적입니다. Mongoose의 populate 기능을 사용하여 관련 데이터를 결합할 수 있지만, 이는 추가적인 쿼리를 발생시키며 성능에 영향을 줄 수 있습니다.
  • 데이터 일관성 관리: 별도의 컬렉션으로 데이터를 관리할 때, 데이터 간의 관계를 수동으로 관리해야 합니다.
  •  

2. users 컬렉션 내에 expenses, incomes를 하부 문서로 포함

장점

  • 데이터 일관성: 한 문서 내에서 관련 데이터를 관리함으로써, 데이터 간의 관계를 명확하게 유지할 수 있습니다.
  • 단순한 쿼리: 관련 데이터를 함께 조회할 때 추가적인 조인이나 쿼리 없이 단일 문서 조회로 가능합니다.

단점

  • 문서 크기 제한: MongoDB에서 단일 문서의 크기는 16MB로 제한됩니다. 사용자의 expenses와 incomes 데이터가 많아지면 이 제한에 도달할 수 있습니다.
  • 확장성 제한: 많은 양의 expenses와 incomes 데이터를 저장해야 하는 경우, 성능 저하나 관리의 복잡성이 증가할 수 있습니다.
  •  

결론

  • 대규모 데이터를 다루거나 확장성이 중요한 경우 : 별도의 컬렉션을 사용하는 것을 추천합니다. 이는 더 유연한 데이터 관리와 성능 최적화를 가능하게 합니다.
  • 관련 데이터의 일관성과 간단한 쿼리가 더 중요한 경우 : 또는 애플리케이션에서 관리해야 하는 데이터의 양이 비교적 작은 경우, 컬렉션1의 내에  하부 문서로 포함하는 방식을 추천합니다.

하부 참조든, 같은 콜렉션으로 참조하든 일단 둘다 ref는 써야함.

그렇게 특정 user의 objectId를 참조하게 되어 그 내용만 각 collection2, collection3에서 불러올 수 있다.

이전처럼 require을 서로 안해주어도 User라는 model즉 콜렉션을 참고하게 해준다.

 

1. collecion1의 참조를 통한 관리하기.

const mongoose = require("mongoose");

// User 스키마 정의
const UserSchema = new mongoose.Schema(
  {
    username: { type: String, required: true, trim: true, unique: true },
    email: { type: String, required: true, trim: true, unique: true },
    password: { type: String, required: true, trim: true },
    picture: { type: String },
    // 'expenses'와 'incomes' 필드 제거
  },
  { timestamps: true }
);

const User = mongoose.model("User", UserSchema);

module.exports = User;

 

 

관리 되는 collection들은 아래처럼 ref를 통해 참조.

const ExpenseSchema = new mongoose.Schema(
  {
    title: { type: String, required: true, trim: true, maxLength: 50 },
// 생략
    user: { type: mongoose.Schema.Types.ObjectId, ref: "User" }, // 특정 user의 _id 참조 
  },
  { timestamps: true, _id: true }
);

const Expense = mongoose.model("Expense", ExpenseSchema);

 


2. 하부 참조로 관리하기.

 

user에서 배열을 통해 관리하게끔 한다.

const UserSchema = new mongoose.Schema({
  username: { type: String, required: true, trim: true, unique: true },
 
  expenses: [ExpenseSchema], // ExpenseSchema를 내장 문서로 포함
 
}, { timestamps: true });

 

const ExpenseSchema = new mongoose.Schema(
  {
    title: { type: String, required: true, trim: true, maxLength: 50 },
   //생략
    user: { type: mongoose.Schema.Types.ObjectId, ref: "User" }, // 특정 user의 _id 참조 
  },
  { timestamps: true, _id: true }
);

 

_id를 따로 생성해줘야 한다.


// User 문서 예시
{
  _id: ObjectId("60af904685153de0f4e331f2"),
  username: "user1",
  email: "user1@example.com",
  // 기타 필드...
}

// Expense 문서 예시
{
  _id: ObjectId("60af906885153de0f4e331f3"),
  title: "점심 식사",
  amount: 12000,
  date: new Date(),
  category: "식비",
  description: "회사 근처 식당에서 점심 식사",
  user: ObjectId("60af904685153de0f4e331f2") // User 문서를 참조
}

// Income 문서 예시
{
  _id: ObjectId("60af908765153de0f4e331f4"),
  title: "프리랜스 프로젝트",
  amount: 500000,
  date: new Date(),
  category: "부수입",
  description: "웹 개발 프로젝트 완료",
  user: ObjectId("60af904685153de0f4e331f2") // User 문서를 참조
}

Document - Reference

Reference 저장 방법은 pointer 개념으로 이해하면 된다.

Embedded 방식의 Document를 통째로 저장하는것이 아니라 참조 할 수 있도록 ID를 저장하는 방식이다.

 

예를들어, 2가지 종류의 Publisher Document / Book Document가 있을때, Book Document의 publisher_id  Publisher._id 의 value 를 저장하는 것이다.

RDBMS의 외래키와 같은 개념이라고 봐도 되며, 이렇게 _id를 저장해주면 몽고디비가 알아서 찾아 연결해준다.