본문으로 건너뛰기

JSON 데이터베이스

Connect Base의 NoSQL JSON 데이터베이스 심화 가이드입니다.

개요

Connect Base JSON 데이터베이스는 스키마 없이 시작할 수 있는 유연한 NoSQL 데이터베이스입니다. JSON 형식으로 데이터를 저장하고 강력한 쿼리 기능을 제공합니다.

앱 내에서 테이블을 직접 생성하여 데이터를 관리합니다. 별도의 데이터베이스 그룹 없이 앱 단위로 테이블을 플랫하게 관리하는 구조입니다.

스키마 설계

스키마리스 접근

테이블 생성 시 스키마를 정의할 필요가 없습니다:

typescript
// tableId(tbl_xxx)는 콘솔 → 데이터베이스 → 테이블 만들기 후 발급
await cb.database.createData('tbl_users', {
  data: {
    name: '홍길동',
    email: '[email protected]',
    age: 30,
    profile: {
      bio: '개발자입니다',
      avatar: 'https://...'
    },
    tags: ['developer', 'korea']
  }
})

중첩 객체

JSON의 장점을 활용하여 중첩 구조 사용:

typescript
await cb.database.createData('tbl_orders', {
  data: {
    orderId: 'ORD-001',
    customer: {
      name: '홍길동',
      email: '[email protected]',
      address: {
        city: '서울',
        street: '강남대로 123'
      }
    },
    items: [
      { productId: 'P1', quantity: 2, price: 15000 },
      { productId: 'P2', quantity: 1, price: 25000 }
    ],
    totalAmount: 55000
  }
})

쿼리 최적화

필요한 필드만 조회

typescript
// 전체 필드 조회 (비효율)
const all = await cb.database.getData('tbl_users')

// 필요한 필드만 조회 (효율적)
const partial = await cb.database.queryData('tbl_users', {
  select: ['name', 'email']
})

인덱싱

자주 조회하는 필드에는 인덱스를 설정하세요:

typescript
// 콘솔에서 인덱스 설정
// 테이블 > 설정 > 인덱스 추가
// 필드: email, 유형: 고유 인덱스

페이지네이션

대량 데이터 조회 시 반드시 페이지네이션 사용:

typescript
// 첫 페이지
const page1 = await cb.database.queryData('tbl_users', {
  limit: 20,
  offset: 0,
  orderBy: 'created_at',
  orderDirection: 'desc'
})

// 다음 페이지
const page2 = await cb.database.queryData('tbl_users', {
  limit: 20,
  offset: 20,
  orderBy: 'created_at',
  orderDirection: 'desc'
})

고급 쿼리

복합 조건

typescript
const results = await cb.database.queryData('tbl_products', {
  where: {
    category: 'electronics',
    price: { $gte: 10000, $lte: 100000 },
    stock: { $gt: 0 }
  }
})

OR 조건

typescript
const results = await cb.database.queryData('tbl_users', {
  where: {
    $or: [
      { role: 'admin' },
      { role: 'moderator' }
    ]
  }
})

배열 검색

typescript
// 태그 포함 여부
const developers = await cb.database.queryData('tbl_users', {
  where: {
    tags: { $contains: 'developer' }
  }
})

모범 사례

1. 데이터 정규화 vs 비정규화

비정규화 (권장 상황):

  • 읽기가 쓰기보다 훨씬 많을 때
  • 데이터 일관성이 덜 중요할 때
typescript
// 주문에 고객 정보 복사 (비정규화)
{
  orderId: 'ORD-001',
  customerName: '홍길동',  // 복사됨
  customerEmail: '[email protected]'  // 복사됨
}

정규화 (권장 상황):

  • 데이터 일관성이 중요할 때
  • 데이터 업데이트가 자주 일어날 때
typescript
// 주문에 고객 ID만 저장 (정규화)
{
  orderId: 'ORD-001',
  customerId: 'user_123'  // 참조만
}

2. 배열 크기 제한

배열이 무한정 커지지 않도록 주의:

typescript
// ❌ 나쁜 예: 배열이 무한정 커질 수 있음
{
  userId: 'user_123',
  loginHistory: [/* 수천 개... */]
}

// ✅ 좋은 예: 별도 테이블로 분리
// logins 테이블
{
  userId: 'user_123',
  timestamp: '2024-01-15T10:00:00Z'
}

3. 일관된 필드 타입

같은 필드에는 항상 같은 타입 사용:

typescript
// ❌ 나쁜 예: 타입 혼용
{ age: 30 }      // number
{ age: "30" }    // string

// ✅ 좋은 예: 일관된 타입
{ age: 30 }
{ age: 25 }