본문 바로가기

코딩/project

pj, 7일차


Sequelize
- node.js.에서 mysql 등 RDBMS를 쉽게 다룰 수 있도록 도와주는 라이브러리

    npm i sequelize 

 

https://sequelize.org/

MongoDB
- MongoDB는 NoSQL 데이터베이스로 문서 기반 데이터 저장 방식을 채택한 오픈소스 DBMS
- 관계형 데이터베이스와는 달리 스키마가 없으며, BSON(Binary JSON) 형태로 데이터를 저장
- 유연성이 좋고, 대규모 데이터 처리에 용이


MongoDB Atlas
- MongoDB의 관리형 클라우드 데이터베이스 서비스
- MongoDB 데이터베이스를 클라우드에서 호스팅 하고 관리하는 것을 중심으로 하며, 개발자 및 기업이 손쉽게 애플리케이션을 빌드하고  배포할 수 있도록 지원

 

// db/database.js

import mysql from 'mysql2';
import { config } from '../config.js';
import SQ from 'sequelize';

const { host, user, database, password } = config.db;

export const sequelize = new SQ.Sequelize(database, user, password, {
    host,
    dialect: 'mysql',
    logging: false
})

 

// app.js

// app.js

import express from "express";
import morgan from "morgan";
import tweetsRouter from './router/tweets.js'
import authRouter from './router/auth.js'
import { config } from "./config.js";
import { sequelize } from "./db/database.js";

const app = express();

app.use(express.json());  // json로 연결
app.use(morgan("dev"));

//tweetsRouter 미들웨어 등록
app.use('/tweets', tweetsRouter);  
//authsRouter 미들웨어 등록
app.use('/auth', authRouter); 

app.use((req, res, next) => {
    res.sendStatus(404);
});

// DB 연결 테스트!
// db.getConnection().then(Connection => console.log(Connection));
sequelize.sync().then(() => {
    app.listen(config.host.port);
});


// app.listen(config.host.port);

 

// data/tweet.js

// data/tweet.js

// import { db } from '../db/database.js';

import SQ from 'sequelize';
import { sequelize } from '../db/database.js';
import { User } from './auth.js';

const DataTypes = SQ.DataTypes;
const Sequelize = sequelize;

const INCLUDE_USER =  {
    attributes: [
        'id',
        'text',
        'createdAt',
        'userId',
        [Sequelize.col('user.name'), 'name'],
        [Sequelize.col('user.username'), 'username'],
        [Sequelize.col('user.url'),'url']
    ],
    include: {
        model: User,
        attributes : [],
    }
}

const ORDER_DESC = {
    order: [['createdAt', 'DESC']]
}

// const SELECT_JOIN = 'select tw.id, tw.text, tw.createdAt, tw.userId, us.username, us.email, us.url from tweets as tw join users as us on tw.userId = us.id';

// const ORDER_DESC = 'order by tw.createdAt desc';

const Tweet = sequelize.define(
    'tweet',
    {
        id: {
            type: DataTypes.INTEGER,
            autoIncrement: true,
            allowNull: false,
            primaryKey: true
        },
        text: {
            type: DataTypes.TEXT,
            allowNull: false
        }
    },
    { timestamps: false }
);

Tweet.belongsTo(User);


// 모든 트윗을 리턴
export async function getAll() {
    return Tweet.findAll({ ...INCLUDE_USER, ...ORDER_DESC });

    // return db.execute(`${SELECT_JOIN} ${ORDER_DESC}`).then ((result) => {
    //     console.log(result);
    //     return result;
    // });
}

// 해당 아이디에 대한 트윗을 리턴
export async function getAllByUsername(username){
    return  Tweet.findAll({ ...INCLUDE_USER, ...ORDER_DESC, include: {
        ...INCLUDE_USER.include, where: {username}
    } });

    // return db.execute(`${SELECT_JOIN} where username = ? ${ORDER_DESC}`, [username]).then ((result) => {
    //     console.log(result);
    //     return result;
    // });
}

// 글번호에 대한 트윗을 리턴
export async function getById(id){
    return Tweet.findOne({ where: {id}, ...INCLUDE_USER });

    // return db.execute(`${SELECT_JOIN} where tw.id = ? ${ORDER_DESC}`, [id]).then ((result) => {
    //     console.log(result);
    //     return result;
    // });
}

// 트윗을 작성
export async function create(text, userId){
    return Tweet.create({ text, userId }).then((data) => this.getById(data.dataValues.id));

    // return db.execute('insert into tweets (text, userId) values (?, ?)', [text, userId]).then ((result) => {
    //     console.log(result);
    //     return getById(result[0].insertId);
    // });
}

// 트윗을 변경
export async function update(id, text){
    return Tweet.findByPk(id, INCLUDE_USER).then((tweet) => {
        tweet.text = text;
        return tweet.save();
    })
   
    // return db.execute('update tweets set text = ? where id =?', [text, id]).then ((result) => {
    //     console.log(result);
    //     return getById(id);
    // });
}

// 트윗을 삭제
export async function remove(id){
    return Tweet.findByPk(id).then((tweet) => {
        tweet.destroy();
    })
    // return db.execute('delete from tweets where id = ?', [id]);
}

 

// data/auth.js

// data/auth.js

//import { db } from '../db/database.js';

import SQ from 'sequelize';
import { sequelize } from '../db/database.js';
const DataTypes = SQ.DataTypes;

export const User = sequelize.define(
    'user',
    {
        id: {
            type: DataTypes.INTEGER,
            autoIncrement: true,
            allowNull: false,
            primaryKey: true
        },
        username: {
            type: DataTypes.STRING(50),
            allowNull: false
        },
        password: {
            type: DataTypes.STRING(150),
            allowNull: false
        },
        name: {
            type: DataTypes.STRING(50),
            allowNull: false
        },
        email: {
            type: DataTypes.STRING(50),
            allowNull: false
        },
        url: DataTypes.STRING(1000)
    },
    { timestamps: false }
);

// 아이디(username) 중복 검사 
export async function findByUsername(username){
    return User.findOne({where: {username}});
}

// id 중복 검사 
export async function findById(id){
    return User.findByPk(id);
}

export async function createUser(user){
    return User.create(user).then((data) => data.dataValues.id)
}


// export async function login(username){
//     return users.find((users) => users.username === username);
// }


// {
//     "username":"orange",
//     "password":"12345",
//     "name":"오렌지",
//     "email":"orange@orange.com",
//     "url":"https://img.freepik.com/premium-vector/banana-cute-kawaii-style-fruit-character-vector-illustration_787461-1772.jpg"
// }

 

----------------------------------------------------------------------------------------------------

// .env

# DB
# DB_HOST=127.0.0.1
DB_HOST=mongodb+srv://zmwaexp:<password>@cluster0.ul4snii.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0

DB_PORT=3306
DB_USER=root
DB_PASSWORD=1234
DB_DATABASE=kdt

# JWT
JWT_SECRET=abcd1234%^&*
JWT_EXPORES_SEC=172800

# BCRYPT
BCRYPT_SALT_ROUNDS=10

# SERVER
PORT=8080

 

//app.js

// app.js

import express from "express";
import morgan from "morgan";
import tweetsRouter from './router/tweets.js'
import authRouter from './router/auth.js'
import { config } from "./config.js";
// import { sequelize } from "./db/database.js";
import { connectDB } from "./db/database.js";

const app = express();

app.use(express.json());  // json로 연결
app.use(morgan("dev"));

//tweetsRouter 미들웨어 등록
app.use('/tweets', tweetsRouter);  
//authsRouter 미들웨어 등록
app.use('/auth', authRouter); 

app.use((req, res, next) => {
    res.sendStatus(404);
});

// DB 연결 테스트!
// db.getConnection().then(Connection => console.log(Connection));
// sequelize.sync().then(() => {
//     app.listen(config.host.port);
// });


connectDB().then((db) => {
    console.log('몽고DB 연결 성공!!');
    app.listen(config.host.port);
}).catch(console.error);

// app.listen(config.host.port);

 

// db/database.js

import { config } from '../config.js';
import MongoDB from 'mongodb';
let db;
export async function connectDB(){
    return MongoDB.MongoClient.connect(config.db.host).then((client) => db = client.db());
}
export function getUsers(){
    return db.collection('users');   //데이터를 넣을 때 users객체에 넣겠다
}
export function getTweets(){
    return db.collection('tweets');
}

 

// data/auth.js

// data/auth.js
import MongoDB from 'mongodb';
import { getUsers } from '../db/database.js';

const ObjectID = MongoDB.ObjectId;

//import { db } from '../db/database.js';
// import MongoDB from 'mongodb';
// // import SQ from 'sequelize';
// // import { sequelize } from '../db/database.js';
// const DataTypes = SQ.DataTypes;

// export const User = sequelize.define(
//     'user',
//     {
//         id: {
//             type: DataTypes.INTEGER,
//             autoIncrement: true,
//             allowNull: false,
//             primaryKey: true
//         },
//         username: {
//             type: DataTypes.STRING(50),
//             allowNull: false
//         },
//         password: {
//             type: DataTypes.STRING(150),
//             allowNull: false
//         },
//         name: {
//             type: DataTypes.STRING(50),
//             allowNull: false
//         },
//         email: {
//             type: DataTypes.STRING(50),
//             allowNull: false
//         },
//         url: DataTypes.STRING(1000)
//     },
//     { timestamps: false }
// );

// // 아이디(username) 중복 검사
export async function findByUsername(username){
    return getUsers().find({username}).next().then(mapOptionalUser);
} 
// export async function findByUsername(username){
//     return User.findOne({where: {username}});
// }

// // id 중복 검사 
export async function findById(id){
    return getUsers().find({_id: new ObjectID(id)}).next().then(mapOptionalUser);
}
// export async function findById(id){
//     return User.findByPk(id);
// }

export async function createUser(user){
    return getUsers().insertOne(user).then((result) => console.log(result.insertedId.toString()));
}

// export async function createUser(user){
//     return User.create(user).then((data) => data.dataValues.id)
// }


function mapOptionalUser(user){
    return user ? { ...user, id: user._id.toString() } : user;
}

// export async function login(username){
//     return users.find((users) => users.username === username);
// }


// {
//     "username":"orange",
//     "password":"12345",
//     "name":"오렌지",
//     "email":"orange@orange.com",
//     "url":"https://img.freepik.com/premium-vector/banana-cute-kawaii-style-fruit-character-vector-illustration_787461-1772.jpg"
// }

 

// data/tweet.js

// data/tweet.js

// import { db } from '../db/database.js';

// import SQ from 'sequelize';
//import { sequelize } from '../db/database.js';

import MongoDB from 'mongodb';
import { getTweets, getUsers } from '../db/database.js';
import * as authRepository from './auth.js';


const ObjectID = MongoDB.ObjectId;

// import { User } from './auth.js';

// 모든 트윗을 리턴
export async function getAll() {
    return getTweets().find().sort({ createdAt: -1 }).toArray().then(mapTweets);
}


// 해당 아이디에 대한 트윗을 리턴
export async function getAllByUsername(username){
    return getTweets().find({username}).sort({createdAt: -1 }).toArray().then(mapTweets);
}

// 글번호에 대한 트윗을 리턴
export async function getById(id){
    return getTweets().find({ _id: new ObjectID(id)}).next().then(mapOptionalTweet);
}


// 트윗을 작성
export async function create(text, userId){
    return authRepository.findById(userId).then((user) => getTweets().insertOne({
        text,
        userId,
        username: user.username,
        url: user.url
    })).then((result) => getById(result.insertedId)).then(mapOptionalTweet);
}


// 트윗을 변경
export async function update(id, text){
    return getTweets().findOneAudUpdate({_id: new ObjectID(id)}, {$set: {text}}, {returnDocument: 'after'}).then((result) => result).then(mapOptionalTweet);
}
   

// 트윗을 삭제
export async function remove(id){
    return getTweets().deleteOne({_id: new ObjectID(id)});
}

function mapTweets(tweets){
    return tweets.map(mapOptionalTweet);
}

function mapOptionalTweet(tweet){
    return tweet ? { ...tweet, id: tweet.insertedId} : tweet;
}

 

 

🤍

 

ChatGPT에게 물어본 오늘의 공부-

 

✔️ Sequelize

Sequelize는 Node.js 어플리케이션을 위한 ORM(Object-Relational Mapping) 라이브러리입니다. 이 라이브러리는 주로 SQL 데이터베이스를 다룰 때 사용되며, JavaScript로 쿼리를 작성하는 대신에 객체 지향적인 방식으로 데이터베이스와 상호작용할 수 있도록 도와줍니다. Sequelize를 사용하면 데이터베이스의 테이블을 JavaScript 클래스로 모델링할 수 있으며, 이를 통해 데이터를 쉽게 생성, 조회, 수정 및 삭제할 수 있습니다.

Sequelize의 주요 기능 및 장점은 다음과 같습니다:

  1. 객체 지향적인 모델링: 데이터베이스 테이블을 JavaScript 클래스로 표현하여 코드를 보다 직관적으로 만듭니다.
  2. 데이터 유효성 검사: 모델에 데이터를 삽입하기 전에 유효성을 검사하고 오류를 방지합니다.
  3. 쿼리 생성 및 실행: Sequelize는 쿼리를 생성하고 실행하는 다양한 방법을 제공하여 SQL 작성을 간소화합니다.
  4. 데이터베이스 간 이식성: Sequelize는 다양한 SQL 데이터베이스를 지원하여 코드의 이식성을 높입니다.
  5. 마이그레이션 지원: 데이터베이스 스키마의 변경 사항을 관리하고 적용할 수 있는 마이그레이션 도구를 제공합니다.

이러한 기능들을 통해 Sequelize는 Node.js 기반 어플리케이션의 데이터베이스 관련 작업을 보다 쉽고 효율적으로 처리할 수 있도록 도와줍니다.

 
 
✔️ INCLUDE_USER

이 형식은 Sequelize 쿼리에서 사용되는 옵션 객체입니다. Sequelize는 Node.js에서 사용되는 ORM(Object-Relational Mapping) 라이브러리로, 데이터베이스 테이블과 JavaScript 객체 간의 매핑을 도와줍니다.

위의 코드에서 INCLUDE_USER는 Sequelize에서 쿼리를 수행할 때 사용되는 옵션 객체로, 특정 모델에 대한 쿼리를 실행할 때 해당 모델과 연결된 다른 모델의 데이터도 함께 가져올 수 있도록 설정합니다.

해당 코드에서 사용된 옵션은 다음과 같습니다:

  • attributes: 가져올 열(column)을 지정합니다. 여기서는 트윗(tweets) 테이블의 id, text, createdAt, userId 및 사용자(user) 테이블의 name, username, url을 지정합니다. Sequelize.col을 사용하여 사용자 모델의 특정 열에 대한 별칭을 설정합니다.
  • include: 연결된 모델의 데이터를 가져오도록 지정합니다. 여기서는 User 모델을 가져오도록 설정합니다.

이렇게 함으로써 Sequelize는 트윗 테이블과 사용자 테이블을 조인하여 필요한 데이터를 함께 가져올 수 있게 됩니다

 

✔️ sequelize.define()

sequelize.define() 함수는 Sequelize에서 모델을 정의할 때 사용됩니다. 이 함수를 사용하여 데이터베이스 테이블의 모델을 JavaScript 객체로 정의하고 Sequelize 모델을 생성합니다. 이를 통해 JavaScript 코드를 사용하여 데이터베이스 테이블에 대한 작업을 수행할 수 있습니다.

일반적으로 다음과 같은 방식으로 sequelize.define() 함수를 사용합니다:

 

이와 같이 정의된 모델은 Sequelize 모델로 사용될 수 있으며, 이를 통해 해당 테이블에 대한 쿼리 및 데이터 조작 작업을 수행할 수 있습니다.

 

✔️ belongsTo()

belongsTo() 함수는 Sequelize에서 관계를 정의할 때 사용되는 함수 중 하나입니다. 이 함수는 다른 모델에 대한 외부 키(foreign key)가 현재 모델에 속함을 나타내는 일대일 또는 일대다 관계를 정의할 때 사용됩니다.

예를 들어, 사용자(User) 모델과 게시물(Post) 모델이 있다고 가정해봅시다. 각각의 게시물은 특정 사용자에게 속하므로(Post 모델은 User 모델에 속함), 게시물(Post) 모델은 사용자(User) 모델과 일대다 관계를 가집니다.

이러한 관계를 정의하기 위해 belongsTo() 함수를 사용할 수 있습니다. 예를 들어:

 

 

위의 코드에서 Post.belongsTo(User, { foreignKey: 'userId' })는 "게시물(Post) 모델은 사용자(User) 모델에 속한다"는 의미입니다. foreignKey 옵션은 외부 키의 이름을 정의하며, 위의 예시에서는 userId가 사용되었습니다. 이것은 게시물 테이블에서 사용자를 식별하기 위한 외부 키입니다.

belongsTo() 함수를 사용하면 두 모델 사이의 관계를 설정할 수 있고, 이를 통해 Sequelize가 적절한 SQL 쿼리를 생성하여 데이터베이스에서 관련된 데이터를 가져오거나 조작할 수 있습니다.

 

 

 

✔️ { include: }

{ include: }는 Sequelize에서 쿼리 실행 시 관련된 모델의 데이터를 함께 가져오기 위한 옵션입니다. 이 옵션을 사용하면 주요 모델과 연결된 다른 모델의 데이터를 함께 조회할 수 있습니다.

예를 들어, 사용자(User)와 사용자가 작성한 게시물(Post)이라는 두 모델이 있다고 가정해보겠습니다. 사용자 모델에는 많은 게시물이 연결되어 있습니다. 이때 User.findAll()로 사용자 목록을 가져오면서 각 사용자의 게시물도 함께 가져오고 싶을 수 있습니다. 이때 { include: Post }를 사용하여 게시물 정보를 가져올 수 있습니다.

예를 들어:

 

위의 코드에서 User.findAll()로 모든 사용자를 가져오면서 { include: Post }로 각 사용자의 게시물 정보를 함께 가져옵니다. 이렇게 하면 Sequelize가 내부적으로 조인(join)을 수행하여 연결된 모델의 데이터를 가져올 수 있습니다.

{ include: } 옵션을 사용하여 연결된 모델의 데이터를 함께 가져오면 데이터베이스에서 여러 테이블을 조인하여 한 번의 쿼리로 모든 데이터를 효율적으로 가져올 수 있습니다.

 

✔️ { where: }

{ where: } 옵션은 Sequelize에서 데이터베이스 쿼리를 수행할 때 조건을 지정하는 데 사용됩니다. 이 옵션을 사용하면 특정 조건을 만족하는 레코드만 검색하거나 업데이트할 수 있습니다.

예를 들어, 다음과 같이 where 옵션을 사용하여 사용자 테이블에서 특정 조건을 만족하는 사용자를 검색할 수 있습니다

 

 

위의 예제에서는 User 모델에서 id가 1인 사용자를 검색하고 있습니다. 이렇게 하면 데이터베이스에서 id가 1인 사용자를 검색하여 해당 사용자 객체를 반환합니다.

where 옵션은 여러 가지 비교 연산자를 사용하여 더 복잡한 조건을 지정할 수도 있습니다. 예를 들어, Op.gt, Op.lt 등의 Sequelize의 연산자를 사용하여 범위 검색을 수행할 수 있습니다.

 

 

위의 예제에서는 age가 18보다 크고 30보다 작은 사용자를 검색합니다. 이러한 방식으로 where 옵션을 사용하여 특정 조건을 만족하는 레코드를 검색할 수 있습니다.

 

 

✔️ dataValues

dataValues는 Sequelize 모델 인스턴스에서 실제로 저장된 데이터를 포함하는 객체입니다. Sequelize는 모델 인스턴스를 표현하는데, 이 인스턴스는 데이터베이스의 레코드를 나타냅니다. dataValues 속성은 이 레코드의 각 열(column)과 해당 값에 대한 키-값 쌍을 포함합니다.

예를 들어, 다음과 같이 Sequelize를 사용하여 데이터베이스에서 사용자를 검색한 후 결과로 반환된 인스턴스의 dataValues를 확인할 수 있습니다.

 

 

위의 코드에서 user.dataValues는 데이터베이스에서 검색된 사용자의 정보를 포함하는 객체입니다. 이 객체에는 사용자의 각 열에 대한 정보가 키-값 쌍으로 포함되어 있습니다.

주의할 점은 dataValues는 실제 데이터를 포함하는 객체이므로 수정된 내용은 dataValues에 반영되지만 원본 모델 인스턴스에는 반영되지 않습니다. 따라서 Sequelize에서 데이터를 조작할 때 주로 dataValues를 사용하여 데이터를 읽거나 수정합니다.

 

🤍

'코딩 > project' 카테고리의 다른 글

pj, 8일차  (0) 2024.05.10
pj, 6일차  (0) 2024.05.08
pj, 5일차  (0) 2024.05.03
pj, 4일차  (0) 2024.05.02
pj, 3일차  (0) 2024.04.30