분류 Nodejs

GraphQL, Sequelize 및 PostgreSQL을 위한 NodeJS 상용구

컨텐츠 정보

  • 조회 68 (작성일 )

본문

관계형 데이터를 문서로 노출하는 매력적인 방법.


이 기사에서는 정규화 된 관계형 데이터 (1-n, m-n 카디널리티)를 데이터의 문서 기반 표현에 연결하기 위해 PostgreSQL에 연결된 GraphQL 및 Sequelize의 통합과 함께 제공되는 NodeJS 앱을 살펴볼 것입니다.

GraphQL 읽기 전용 쿼리 예제를 제공하고 Object Relational Mapper Sequelize를 통해 효과적인 SQL 문으로 변환되는 방법을 보여 드리겠습니다.


빠른 시작을 위해 이 문서에서는 이 GH 저장소에 대한 작업 예제를 제공합니다.


Image for post 


프로젝트 설정 


  • graphql-sequelize-pg 프로젝트를 복제하십시오.
    git clone https://github.com/thomasreinecke/graphql-sequelize-pg.git-프로젝트가 ROJECT_HOME 디렉토리에 복제됩니다.
  • PROJECT_HOME에서 yarn을 실행하여 노드 종속성을 설치하십시오.
  • PostgreSQL 데이터베이스 서버를 설치하고 실행되고 액세스 가능한지 확인합니다 (이 자습서에서는 이 항목을 다루지 않지만 인터넷에서 많은 리소스를 찾을 수 있음).
  • PROJECT_HOME에서 .env 파일을 편집하고 데이터베이스 설정을 적용하십시오.

NODE_ENV=development
PORT=9000
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=its-my-database
DB_USERNAME=its-me
DB_PASSWORD=its-my-password
DB_SCHEMA=its-my-schema
DB_DIALECT=postgres 


  • 데이터베이스 스키마 yarn cleandb를 생성하면 데이터베이스 모델과 몇 가지 예제 데이터가 생성되는 것을 볼 수 있습니다.
  • 이제 서버 yarn dev을 시작할 시간입니다

🚀 Sequelize ORM connected to postgres @ 127.0.0.1:5432
🚀 Server ready at http://localhost:4000/
🚀 Subscriptions ready at ws://localhost:4000/graphql 


이 메시지가 표시되면 축하합니다. Sequelize ORM이 PostgreSQL 서버에 연결되어 있고 GraphQL 엔드 포인트가 로컬 컴퓨터에 노출됩니다.


개체 모델 


이 모델은 정확히 하나의 조직 (일대 다 관계)에 속하고 여러 역할 (다 대다 관계)을 수행 할 수 있는 사용자를 제공합니다.

Image for post 

GraphQL 관점에서 스키마는 다음과 같이 설명됩니다. 각 GraphQL 스키마 파일에는 개체 정의 자체, 두 개의 입력 정의 (하나는 새 레코드 <Object> Input을 만들고 다른 하나는 개체 <Object> RecordInput의 정확히 하나의 레코드를 쿼리하기 위한 것) 및 출력이 포함되어 있음을 알 수 있습니다. 개체 및 추가 메타 데이터에 대한 하나 이상의 레코드를 전달할 수 있는 개체입니다. 나중에 GraphQL Playground에서 이러한 정의를 사용할 것입니다.


GraphQL 개체 : 조직 


여러 사용자가 연관 될 수 있는 매우 간단한 조직 표현입니다.


type Org {
id: ID
name: String
}
input OrgInput {
id: ID
name: String
}
input OrgRecordInput {
id: ID
name: String
}
type OrgOutput {
count: Int
data: [Org]
}



GraphQL 객체 : 역할 


여러 사용자와 연결할 수 있는 역할을 보유하는 또 다른 간단한 개체입니다.


type Role {
id: ID
name: String
}
input RoleInput {
id: ID
name: String
}
input RoleRecordInput {
id: ID
}
type RoleOutput {
count: Int
data: [Role]
}


GraphQL Object : User 


사용자를 설명하기 위한 몇 가지 매우 기본적인 필드를 포함하고 조직 및 사용자와 관련된 여러 역할을 참조하는 사용자 개체입니다.


type User {
id: ID
serial: String
firstName: String
lastName: String
org: Org
roles: [Role]
}
input UserInput {
id: ID
serial: String
firstName: String
lastName: String
org: OrgRecordInput
}
input UserRecordInput {
id: ID
serial: String
}
type UserOutput {
count: Int
data: [User]
}



또한 Sequelize에 대한 개체 모델을 설명해야 합니다. 이 모델을 사용하여 PostgreSQL의 스키마를 관리합니다. 처음에는 이 모델을 통해 필요한 데이터베이스 테이블을 만들고 데이터의 관계형 표현을 JSON으로 일치 시킬 것입니다. 음, 우리를 위해 이 작업을 수행하는 것은 모두 Sequelize입니다. Sequelize에 대한 자세한 내용은 다음을 참조하십시오.


Sequelize Object : Org 


이름 기반 쿼리를 사용하여 데이터에 보다 효율적으로 액세스 할 수 있도록 ID가 UUID 필드이고 이름 필드가 고유 한 String (100) + 이름에 대한 추가 색인 인 테이블 조직을 만들 것입니다.


export default (sequelize, DataTypes) => {
const Org = sequelize.define('org',
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4
},
name: {
type: DataTypes.STRING(100),
unique: true,
allowNull: false
}
},
{
freezeTableName: true,
tableName: 'org',
indexes: [
{
unique: false,
fields: ['name']
}
]
}
);
return Org;
};



Sequelize Object : Role 


이 개체는 매우 비슷해 보이며 여기에서 이름에 대한 추가 색인을 만들 것입니다.


export default (sequelize, DataTypes) => {
const Role = sequelize.define('role',
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4
},
name: {
type: DataTypes.STRING(100),
unique: true,
allowNull: false
}
},
{
freezeTableName: true,
tableName: 'role',
indexes: [
{
unique: false,
fields: ['name']
}
]
}
);
return Role;
};



Sequelize Object : User 



User 개체는 orgId 필드를 통해 Org 테이블에 대한 참조와 Sequelize를 통해 생성되는 외래 키 제약 조건을 보유하고 있음을 알 수 있습니다. 이는 사용자와 조직 간의 일대 다 관계를 나타냅니다. 다시 이 고유 필드에 대한보다 효과적인 쿼리를 위해 직렬 필드에 추가 색인을 만들 것입니다.


export default (sequelize, DataTypes) => {
const User = sequelize.define('user',
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4
},
serial: {
type: DataTypes.STRING(10),
unique: true,
allowNull: false
},
firstName: {
type: DataTypes.STRING(100),
allowNull: false
},
lastName: {
type: DataTypes.STRING(100),
allowNull: false
},
orgId: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
}
},
{
freezeTableName: true,
tableName: 'user',
indexes: [
{
unique: false,
fields: ['serial']
}
]
}
);
return User;
};




Data Management 


PostgreSQL에서 데이터베이스 테이블을 생성하는 방법을 간단히 살펴 보겠습니다.


Image for post 

잠깐만 요… 우리는 userrole 테이블에 대한 데이터 모델을 설명하지 않았습니다. 그렇죠? 다행스럽게도 Sequelize는 관계를 잘 관리하므로 그럴 필요가 없습니다.



우리는 조직이 사용자와 일대 다 관계를 갖고 있으며 사용자와 역할이 테이블 userrole을 통해 다 대다 관계에 있음을 명시 적으로 sequelize에 알려줍니다. 그것은 모두 sequelize가 데이터의 정규화를 처리해야 한다는 것입니다. 즉, 사용자 역할 테이블에 상호 참조를 저장하는 것을 의미합니다.


Fetching Data 


이 프로젝트는 GraphQL 플레이 그라운드를 제공하며 http : // localhost : 4000에서 액세스 할 수 있습니다. 이제 GraphQL의 기능을 활용하여 이전에 생성 한 테이블에서 매우 구체적인 데이터를 요청할 수 있습니다.


Query data from : Org 


알려진 모든 조직을 표시하려면 다음 graphQL 쿼리를 사용하십시오.


query {
org {
count
data {
id
name
}
}
} 



데이터 (조직 배열)와 개수에 대한 멋진 응답을 얻습니다.


이 예에서 PostgreSQL에 대한 쿼리는 다음과 같습니다.


SELECT “id”, “name” FROM “public”.”org” AS “org” WHERE 1=1; 


Query data from : Role 


역할에 대해서도 똑같이 할 수 있지만 여기서는 데이터의 수와 ID 검색을 건너 뜁니다.


query {
role {
data {
name
}
}
} 


데이터 배열에 매우 구체적인 역할 이름 세트가 있습니다.


이 예에서 PostgreSQL에 대한 쿼리는 다음과 같습니다.


SELECT "name" FROM "public"."role" AS "role" WHERE 1=1; 


꽤 깔끔하지만 아직 너무 화려하지는 않습니다. 조직 및 역할에 대한 1-n 및 n-m 관계가 모두 결합 된 사용자를 살펴 보겠습니다.


Query data from : User 


다음 쿼리는 조직 이름 및 사용자가 가진 역할 목록을 포함하여 사용자의 세부 정보를 요청합니다.


query {
user {
count
data {
serial
firstName
lastName
org {
name
}
roles {
name
}
}
}
} 



이제 조직과 역할이 사용자 레코드에 메시 된 중첩 된 개체로 표시되지만 사용자는 하나의 조직에만 연결될 수 있고 역할은 JSON 개체의 배열로 표시되므로 사용자는 JSON 개체로 표시됩니다. Tina처럼 여러 역할을 가질 수 있습니다.


이 예에서 PostgreSQL에 대한 쿼리는 다음과 같습니다.


SELECT
"user"."id",
"user"."serial",
"user"."firstName",
"user"."lastName",
"user"."orgId",
"user"."createdAt",
"user"."updatedAt",
"org"."id" AS "org.id",
"org"."name" AS "org.name",
"org"."createdAt" AS "org.createdAt",
"org"."updatedAt" AS "org.updatedAt",
"roles"."id" AS "roles.id",
"roles"."name" AS "roles.name",
"roles"."createdAt" AS "roles.createdAt",
"roles"."updatedAt" AS "roles.updatedAt",
"roles -> userrole"."userId" AS "roles.userrole.userId",
"roles -> userrole"."roleId" AS "roles.userrole.roleId",
"roles -> userrole"."createdAt" AS "roles.userrole.createdAt",
"roles -> userrole"."updatedAt" AS "roles.userrole.updatedAt"
FROM
"public"."user" AS "user"
LEFT OUTER JOIN
"public"."org" AS "org"
ON "user"."orgId" = "org"."id"
LEFT OUTER JOIN
(
"public"."userrole" AS "roles -> userrole"
INNER JOIN
"public"."role" AS "roles"
ON "roles"."id" = "roles -> userrole"."roleId"
)
ON "user"."id" = "roles -> userrole"."userId"
WHERE
1 = 1;



요약 


1n 및 n-m 관계가 있는 매우 간단한 관계형 데이터 모델을 Sequelize를 통해 PostgreSQL에서 JSON으로 관리하고 매핑 하는 방법을 살펴 보았습니다. 사용자 편의를 위해 JSON 데이터는 GraphQL을 통해 사용자에게 전달됩니다.


이 기사에서는 읽기 전용 작업에 중점을 두었습니다. 전체 CRUD 작업에 대한 또 다른 기사를 제공 할 계획입니다. 계속 지켜봐 주세요…