์ฃผ์ ์์
- ์นด๋๊ฐ ์์ ๋, ์นด๋ column์ด ๋จ์ง ์๋ ํ์ ๊ณ ์น๊ธฐ(์ฟผ๋ฆฌ๋ฌธ ์์ ) โ 2024-09-05
- ๋๋๊ทธ ์ค ๋๋กญ์ db์ order ๋ฐ์ โ 2024-09-05
- ์ ๋ ฌ ์ ๋๋ฉ์ด์ โ 2024-09-05
ํ์ต ํค์๋
- sql join โ 2024-09-05
๊ณ ๋ฏผ ๋ฐ ํด๊ฒฐ๊ณผ์
๋น Column์ ๊ฐ์ ธ์ค์ง ๋ชปํ๋ ์๋ฌ
๊ธฐ์กด์ ๊ฒฝ์ฐ ๋ชจ๋ ์นด๋๋ค์ ์ ๋ณด๋ฅผ
```sql
select * from todo_cards where username = ?
```
์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋ชจ๋ ์นด๋๋ค์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ model์์ ์ด๋ฅผ column ๋ณ๋ก ๋๋์ด ๊ฐ๊ณตํ ๋ค ๋ค์๊ธ ํด๋ผ์ด์ธํธ์ response body๋ฅผ ๋ฃ์ด response๋ฅผ ๋ณด๋ด์ฃผ๋ ๋ฐฉ์์ผ๋ก ์ค๊ณํ์์ต๋๋ค.
ํ์ง๋ง ์ด๋ฌํ sql๋ฌธ์ ๋ฌธ์ ๋ todo_cards์ ๋ชจ๋ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๊ธฐ๋ง ํ ๋ฟ, column๋ค์ ๋ํ ์ ๋ณด๋ฅผ ๋ฐ๋ก ๊ฐ์ ธ์ค์ง ์์์ผ๋ฏ๋ก task_column ํ
์ด๋ธ์ ๋ง์ฝ ์ด๋ ํ ์นด๋๋ ์์ ๊ฒฝ์ฐ todo_cards์๋ ์๋ฌด๊ฒ๋ ์๋ column์ ์ ๋ณด๋ ๋์ค์ง ์๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ joinํ๋ ๋ฐฉ์์ ํตํด์ ํด๊ฒฐํ์ต๋๋ค.
const query = `
SELECT
todo_cards.task_column,
todo_cards.card_id,
todo_cards.author,
todo_cards.title,
todo_cards.detail,
todo_cards.created_at,
task_columns.username,
task_columns.col_name
FROM
todo_cards
right OUTER JOIN
task_columns
ON
todo_cards.task_column = task_columns.col_name
WHERE task_columns.username = ?
`;์ด๋ฐ ์์ผ๋ก task_column์ right joinํ์ฌ task column์๋ ์์ง๋ง todo_cards์๋ ์๋ ๊ฒ๋ค ๋ํ ๊ฐ์ ธ์์ ๋ค์๊ธ ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ๋๋ก ๋ง๋ค์์ต๋๋ค.
๋๋๊ทธ ์ค ๋๋กญ์ db์ order ๋ฐ์
์ ๋ ๋๋ถ๋ถ์ ์ปดํฌ๋ํธ๊ฐ apiํธ์ถ์ด ์ด๋ฃจ์ด์ง ํ ํด๋น ์ปดํฌ๋ํธ์ ๋ํด์๋ ๋ค์ get์์ฒญ์ ๋ถ๋ฌ์ ๊ฐ์ ธ์จ ์ ๋ณด๋ก ๋ฆฌ๋ ๋๋ง์ ํ๋ค๋ ๊ฒ์ ์ ์ ๋ก ํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๋๋๊ทธ ์ค ๋๋กญ ์์ db์ order์ ์ด๋ป๊ฒ ๋ฐ์ํด์ผ ํ ์ง ๊ณ ๋ฏผ์ด ๋์์ต๋๋ค.
๊ทธ๋ฌ๋ ์ค greenhopper ๋ฐฉ์์ ๋ธ๋ก๊ทธ ๊ธ์์ ์ฐพ๊ฒ ๋์๊ณ , ์ด๋ฅผ ์ด๋ป๊ฒ ํ๋ฉด db์ ํด๋ผ์ด์ธํธ ๋ชจ๋์ ์ ์ฉ์์ผ ๋งค๋๋ฌ์ด ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ง ์ ์์์ง์ ๋ํด์ ๊ณ ๋ฏผํ ๊ฒฐ๊ณผ์ ๋๋ค.
document
.getElementById("sections")
.addEventListener("drop", async (event) => {
try {
const cardId = event.dataTransfer.getData("data");
const targetCard = document.getElementById(cardId);
handleSoftMove(event, cardId);
await handleMoveActionsToServer(cardId, targetCard);
} catch (error) {
console.log(error);
}
});drop ์ด๋ฒคํธ๊ฐ ๋ฐ์์ด ๋๋ฉด ํด๋น ๋๋๊ทธ์ ๋์์ด ๋๋ ํ๊ฒ์ผ๋ก๋ถํฐ dataTransfer๋ฅผ ์ด์ฉํด ํด๋นํ๋ ์นด๋์ ๊ณ ์ ์๋ณ ID๋ฅผ ๊ฐ์ ธ์ค๊ณ ํด๋น ์ปดํฌ๋ํธ๋ฅผ ๋ณ์์ ํ ๋นํ์ต๋๋ค.
function handleSoftMove(event, cardId) {
let closest = getEventTarget(event);
if (!closest) return;
closest.style.borderBottom = "none";
const cardToMove = document.getElementById(cardId);
if (closest.tagName === "SECTION")
closest = closest.querySelector(".todoList");
closest.className === "todoList"
? closest.insertAdjacentElement("afterbegin", cardToMove)
: closest.insertAdjacentElement("afterend", cardToMove);
}
function getEventTarget(event) {
let closest = event.target.closest("ul > div");
if (!closest) closest = event.target.closest("section");
return closest;
}๋ณ์์ ํ ๋น๋ ๋ค์๋ ํ๊ฒ์ ๋ํด์ getEventTargetํจ์๋ฅผ ํตํด ๊ฐ์ฅ ๊ฐ๊น์ด ์์๋ฅผ ๊ฐ์ ธ์ค๊ฒ ๋ฉ๋๋ค. 0์์๋ก๋ ๊ฐ ์นด๋์ ๊ฐ์ฅ ํฐ container์ธ div element๋ฅผ closest๋ฅผ ํตํด ์ฐพ๊ณ , 1์์๋ก๋ ํด๋นํ๋ ์์น์ ์นผ๋ผ์ ๋ํด์ ์ฐพ์ ๋ฆฌํดํฉ๋๋ค. ์ฐพ์ ์์น์ ๋ํด์ ์กฐ๊ฑด๋ฌธ์ ํตํด
- section(column)์ ๊ฒฝ์ฐ โ ๊ฐ์ฅ ์ฒซ๋ฒ์งธ ์์น๋ก ๋ฃ๊ธฐ ์ํด ๋ฐ๋ก card๋ค์ ๋ด๋ ๋ถ๋ชจ ์์์ ul๋ก ์ง์ ํ๋ ์์๋ฅผ ์ฌํ ๋นํฉ๋๋ค.
- ๊ฐ์ฅ ๊ฐ๊น์ด ๊ณณ์ด card์ผ ๊ฒฝ์ฐ โ ํด๋น ์นด๋์ ๋ค์ ์์น์ ์ถ๊ฐํฉ๋๋ค. ์ด๋ ๊ฒ softmove๋ฅผ ๋จผ์ ์ํํ๊ฒ ๋ฉ๋๋ค.
softmove๋ฅผ ์ํํ๋ ์ด์ ๋ ๋ ๊ฐ์ง๊ฐ ์์ต๋๋ค.
function getPriortyAfterMove(target) {
let next = 0,
prev = 0;
if (
target.nextSibling &&
target.nextSibling.nodeType === Node.ELEMENT_NODE
) {
const nextElement = target.nextSibling;
if (nextElement.tagName === "DIV") {
next = parseInt(nextElement.dataset.priority, 10) || 0;
}
}
if (
target.previousSibling &&
target.previousSibling.nodeType === Node.ELEMENT_NODE
) {
const prevElement = target.previousSibling;
if (prevElement.tagName === "DIV") {
prev = parseInt(prevElement.dataset.priority, 10) || 0;
}
}
if (next && prev) return Math.floor((next + prev) / 2);
else if (prev) return prev + 100;
else return 100;
}getPriorityAfterMoveํจ์์์ ๊ฐ๊ฐ ์นด๋์ element์ ์ ์ฅํด๋์๋ ์ฐ์ ์์์ธpriority๋ฅผ ๊ฐ์ ธ์ ๊ณ์ฐํ๊ธฐ ์ํด์์ ๋๋ค.- softmove๋ฅผ ํตํด ๋ฏธ๋ฆฌ db์ ๋ฐ์๋๊ธฐ ์ ์ ์ํ๋ฅผ ๊ทธ๋ ค๋๊ณ ๋ค์๊ธ ๋ ๋๋ง์ ์ํค๋ฉด ๋ณด๋ค ์ฌ์ฉ์ ๊ฒฝํ์ ์ฆ์ง์ํฌ ์ ์๋ค๊ณ ์๊ฐํ์ต๋๋ค.
์ด๋ ๊ฒ softmove๊ฐ ์ด๋ฃจ์ด์ง ํ์๋ api ํธ์ถ โ ์๋ฒ์ ๋ผ์ฐํฐ โ ๋ ํฌ์งํ ๋ฆฌ๋ฅผ ์ด์ฉํด ์ด๋ํ column์ ์ด๋ฆ๊ณผ ์ฐ์ ์์๋ฅผ ๋ณ๊ฒฝํจ์ผ๋ก์จ ์ ์ ํ ์์น์ ์ฐ์ ์์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ ๋๋ง์์ผ ๋ฆฌ๋ ๋๋ง ์์๋ ์์น๊ฐ ๋๊ฐ์ด ๋์ค๋๋ก ๊ตฌํํ์ต๋๋ค.
taskify๋ฅผ spa ๋ฐฉ์์ผ๋ก ๊ตฌํํ๊ธฐ
๊ธฐ๋ณธ์ ์ธ ๋ ์ด์์ ์์ฒด๋ ์๋ฒ์ฌ์ด๋ ๋ ๋๋ง์ผ๋ก ๊ตฌํ์ ํ์ง๋ง, ๊ฐ๊ฐ์ ์ปดํฌ๋ํธ๋ค์ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋ ๋๋ง์ผ๋ก ๊ตฌํ์ ํ์์ต๋๋ค.
ํ์ง๋ง ์ด๋ ๊ฒ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋ ๋๋ง์ผ๋ก ๊ตฌํํ๋ ๊ณผ์ ์์ views ํด๋์ index.jsํ์ผ์ ์ํธ๋ฆฌ ํฌ์ธํธ๋ฅผ ๊ฐ๋ฆฌํค๊ณ , app์์ ๊ฐ ํ์ด์ง์ ๋ํด์ ๋ ๋๋ง์ ์ํค๋๋ก ํ์๋๋ฐ ์ด ๊ณผ์ ์์ ๋ง์ฝ ๋ก๊ทธ์ธ์ด ์ถ๊ฐ๋ ๊ฒฝ์ฐ ๊ฒฝ๋ก๋ฅผ ์
๋ ฅํ ์ ์๋ express.render์ ํน์ฑ์ ์๋ฒ์ฌ์ด๋ ๋ ๋๋ง ๋ฐฉ์์ผ๋ก ๋ค์๊ธ ๋ค๋ฅธ ํ์ด์ง๋ก ์ด๋์ํค๋ ค๋ฉด index.js์ login.js ํ์ผ ๋ชจ๋๋ฅผ ๋๋ ๋ฐฉ๋ฒ๋ฐ์ ์๊ฐ์ด ๋์ง ์์์ต๋๋ค.
ํ์ง๋ง ์ด๋ ๊ฒ ํ๊ฒ ๋๋ฉด ๊ธฐ์กด์ ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ ์์ฒด๊ฐ ๋ฌด์ํด์ง ๋ฟ๋๋ฌ, ๊ธฐ์กด์ ์ฌ์ฉํ๋ Pages ๋๋ ํ ๋ฆฌ๋ ์ ํ ํ์์๋ ๋๋ ํ ๋ฆฌ๊ฐ ๋์ด๋ฒ๋ฆฌ๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ํ์ฉํ ๋ฐฉ๋ฒ์ ๊ณ ๋ฏผํด๋ณด์์ต๋๋ค.
์ฃผ์๋ฅผ ๋ฐ์ ๋์ ์ผ๋ก ํ์ด์ง ๋ ๋๋งํ๊ธฐ
// /app/app.js
import navigation from "../shared/utils/navigation.js";
function entryPoint() {
const pathName = window.location.pathname;
console.log(pathName);
navigation.navigate(pathName);
}
window.onpopstate = navigation.onPageChanged;
document.addEventListener("DOMContentLoaded", entryPoint);๊ธฐ์กด์ mainpage๋ง ์๋ ๋๋ ๋ฉ์ธ ํ์ด์ง๋ง์ ๋ ๋๋ง ์ํค๋ ํจ์๋ฅผ ์คํ์ํค๋ ์ ๋๋ก app.js๋ฅผ ์ฌ์ฉํ์ง๋ง, ๋ก๊ทธ์ธ ํ์ด์ง๊ฐ ์ถ๊ฐ๋จ์ ๋ฐ๋ผ ์ด๋ฅผ pathname์ ๋ฐ๋ผ ํ์ํ ํ์ด์ง๋ฅผ ๋ ๋๋ง ์ํค๋๋ก ๋ฐฉ์์ ๋ฐ๊ฟจ์ต๋๋ค.
app.get("/", isLoggedIn, (req, res, next) => {
res.render("index");
});
app.get("/login", isNotLoggedIn, (req, res, next) => {
res.render("index");
});๋ฐ๋ผ์ ์๋ฒ์์๋ pathname์ ๋ค๋ฅด์ง๋ง, ๋ชจ๋ ํ์ด์ง๋ค์ด entryPoint์์ ์ผ์ด๋๋ ๊ฒ์ ์ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ spa ๋ฐฉ์์ผ๋ก ๋ง๋ค๋ฉด ์ข์ ์ ์ ์๋ฌด๋๋ index๋ง์ ์ํธ๋ฆฌ ํฌ์ธํธ๋ก ์ก๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ pathname์ผ๋ก ์ ์ํ์ ๊ฒฝ์ฐ๋ ์ ๋ถ ํด๋ผ์ด์ธํธ ์ฌ์ด๋์์ ์ ์ด๊ฐ ๊ฐ๋ฅํ๋ค๋ ์ ์ ๋๋ค. ๋ฐ๋ผ์ ์๋ฒ๊ฐ ๋ ๋๋งํ๋ ๊ฒ์ ๊ธฐ์กด index์ ๋ ์ด์์์ ๋ถ๊ณผํ๊ธฐ ๋๋ฌธ์ api๊น์ง ์ฌ์ฉํด์ผ ํ๋ ์๋ฒ์ ์ญํ ์ด ๋ถ๋ด๋๋ ํจ๊ณผ๋ฅผ ๊ฐ์ง๋ค๊ณ ์๊ฐํ์ต๋๋ค.
๋ค์ app.js๋ก ๋์์ค๋ฉด, pathname์ ๋ฐ๋ผ spa๋ฅผ ๊ตฌํํ๊ธฐ ์ํด์๋ navigation ๊ฐ์ฒด๊ฐ ํ์์ ์ด์์ต๋๋ค. ์๋ํ๋ฉด
- pathname ๊ด๋ฆฌ
- ๊ธฐ์กด ๋ ์ด์์์ ์ฌ์ฌ์ฉํ๋ฉด์ body์ ๋ด์ฉ๋ง ๋ฌ๋ผ์ง๊ฒ ํ๋ ๋ฐฉ์
- ํ์ด์ง ์ด๋์ ๋ฐ๋ฅธ ํ์ด์ง๋ณ ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ถ์ด๊ธฐ/๋ผ๊ธฐ ๋ฑ์ ์กฐ๊ฑด์ ๊ฐ์ถฐ์ผ ํ๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ navigation ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ํ์ด์ง๋ฅผ ์ด๋ํ๋ ๋ก์ง์ ๋ด๋นํ๋๋ก ํ์ต๋๋ค
// /shared/utils/navigation.js
import Main from "../../pages/main/index.js";
import Login from "../../pages/login/index.js";
import EventManager from "../../feature/index.js";
export default (function navigation() {
const navigator = {
"/": Main.render,
"/login": Login.render,
};
function navigate(pathname, prev) {
document.body.innerHTML = "";
history.pushState({ pathname: prev }, null, pathname);
navigator[pathname]();
}
function onPageChanged(event) {
document.body.innerHTML = "";
EventManager.detachEvent(event.pathname);
navigator[window.location.pathname]();
}
return {
navigate,
onPageChanged,
};
})();
navigation ๊ฐ์ฒด๋ ์ด๋์๋ ํ์ด์ง ์ด๋์ ์ฐ์ฌ์ผ ๋ก์ง์ด๊ธฐ ๋๋ฌธ์ fsd ๊ณ์ธต ์ค์ shared ๊ณ์ธต์ด ์๋ง์ ์๋ฆฌ์ผ ๊ฒ์ด๋ผ ์๊ฐํด์ ๋ฃ์ด์ฃผ์์ต๋๋ค ํด๋น navigation๊ฐ์ฒด๋ ๋ฑ๋ก๋ pathname์ ๋ฐ๋ผ
- ๊ธฐ์กด ๋ ์ด์์์์ body๋ฅผ ์ด๊ธฐํ
history.pushState๋ฅผ ํ์ฉํ์ฌ ์ด์ ์ฃผ์๊ฐ์ ๊ฐ์ง๊ณ ๋ค๋ก๊ฐ๊ธฐ๋ฅผ ๋๋ ์ ๊ฒฝ์ฐ ์ด์ ๋ํด์ ๋ค์๊ธ ์ฌ๋ฐ๋ฅธ ํ์ด์ง๋ฅผ ๋ ๋๋ง ํ ์ ์๋๋ก ๋ก์ง ๊ตฌ์ฑ- ํ์ด์ง๋ณ ๋ ๋๋ง ํจ์ ์คํ ์ ๊ณผ์ ์ ๊ฑฐ์นฉ๋๋ค. onPageChanged๋ ๊ธฐ์กด ํ์ด์ง๊ฐ ๋ค๋ฅธ ํ์ด์ง๋ก ์ด๋ํ ๋๋ง๋ค ์คํ๋ ์ ์๋๋ก window์ ๋ฑ๋กํด๋์ ์ด๋ฒคํธํธ๋ค๋ฌ์ธ๋ฐ, ์ด๋ ํ์ด์ง๊ฐ ๋ฐ๋ ๋๋ง๋ค ๋ค์๊ธ ์ด๊ธฐํ์ํค๊ณ , ํด๋น ํ์ด์ง์ ํด๋นํ๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ค์ ์ข ํฉํด๋์ ๋ชจ๋์ head์์ ๋ผ์ด๋์ผ๋ก์จ ์๋ฌ๊ฐ ๋ฐ์ํ์ง ์๋๋ก ๊ตฌํํ์ต๋๋ค.
// /feature/index.js
export default (function EventManager() {
const route = {
"/login": "/feature/login/index.js",
"/main": "/feature/main/index.js",
};
function attachEvent(pathname) {
const script = document.createElement("script");
script.src = route[pathname];
script.type = "module";
document.head.appendChild(script);
}
function detachEvent(pathname) {
const script = document.head.querySelector(
`script[src="${route[pathname]}"]`
);
if (script) script.remove();
}
return { attachEvent, detachEvent };
})();
๋ฉ์ธํ์ด์ง์ ์ด๋ฒคํธ๋ฅผ ์ข ํฉํ์ฌ ๋ฑ๋กํ๊ธฐ๋ง ํด์ฃผ๋ feature/index.js๋ ํ์ด์ง๊ฐ ์ถ๊ฐ๋จ์ ๋ฐ๋ผ ํ์ด์ง๋ณ๋ก ๋๋ ํ ๋ฆฌ๋ฅผ ๋ง๋ค์ด depth๋ฅผ ํ๋จ๊ณ ๋๋ฆฌ๋ ๋์ ์, ํ์ด์ง๋ณ๋ก index.js๋ฅผ ๋ฐ๋ก ๋ง๋ค์ด ํด๋น ํ์ด์ง์ ๋ฑ๋ก๋์ด์ผ ํ ์ด๋ฒคํธ ์์๊ณผ ํธ๋ค๋ฌ๋ค์ ์ข ํฉํ์ฌ ๋ฑ๋กํ ์ ์๋๋ก ํด์ฃผ์์ผ๋ฉฐ, ์ด๋ฅผ ์ ๋๊ฒฝ๋ก๋ก ์ค์ ํ์ฌ head์ script๋ก ๋ฃ์ด์ฃผ๋ ๋ฐฉ์์ ์ฌ์ฉํ์ต๋๋ค.
์ง๋ฌธ์ฌํญ
์ ๋ฒ ๋ฆฌ๋ทฐ์์ ๋ง์ํด์ฃผ์ history ํ ์ด๋ธ์ ์ด์ฉํ redo, undo ์กฐ์ธ์ ์ฐธ๊ณ ํ์ฌ history ํ ์ด๋ธ์ ๋ค์ ๊ตฌ์ํจ์ ์์ด์ ์ ๋งคํ ๋ถ๋ถ์ด ์์ด ์ง๋ฌธ๋๋ฆฌ๊ณ ์ถ์ต๋๋ค.
-- `history` ํ
์ด๋ธ
CREATE TABLE `history` (
`history_id` int auto_increment,
`username` varchar(10) NOT NULL,
`action` varchar(10) NOT NULL,
`column_name` varchar(20) NULL,
`title` varchar(20) NULL,
`detail` varchar(500) NULL,
`from_column` varchar(20) NULL,
`to_column` varchar(20) NULL,
`created_at` timestamp NULL,
`card_id` int NOT NULL,
`prev_priority` int NULL,
PRIMARY KEY(`history_id`),
FOREIGN KEY (`username`) REFERENCES `user` (`username`) on delete cascade on update cascade
);
history๋ ๋ชจ๋ action์ ๋ํด ์ ์ฅํด์ผ ํฉ๋๋ค. ํ์ง๋ง ๊ฐ๊ฐ์ action๋ค์ ๋ํด์ ํ์์ ์ผ๋ก ๊ฐ์ ธ์ผ ํ๋ ์ ๋ณด๋ ์กฐ๊ธ์ฉ ๋ค๋ฆ ๋๋ค.
- ์นด๋ ์ด๋ โ ์ด์ ์นผ๋ผ, ์นด๋ id, ๊ฐ ํ์ ์นผ๋ผ
- ์นด๋ ์ญ์ โ ์ญ์ ์ ์นด๋์ ๋ชจ๋ ๋ด์ฉ
- ์นด๋ ์ถ๊ฐ โ ์นด๋ id
- ์นด๋ ์์ โ ์ด์ ์นด๋์ ๋ชจ๋ ๋ด์ฉ ์ด๋ฅผ ์ด๋ป๊ฒ ๊ด๋ฆฌํ๋ฉด ์ข์๊น์ ๋ํด์ ์๊ฐํด๋ดค๋๋ฐ, ํ์์ ์ผ๋ก ๊ฐ์ ธ์ผ ํ๋ ๊ฐ๋ง NOT NULL๋ก ๋๊ณ , ๋ค๋ฅธ ์นผ๋ผ์ ๋ํด์๋ NULL๋ก ์ค์ ํด๋ ์์ด๋ ๋๋ ๊ฒฝ์ฐ์๋ NULL๊ฐ์ผ๋ก ๋ ์ ์๋๋ก ํด๋จ์ต๋๋ค. ํ์ง๋ง ์ด๋ ๊ฒ ๊ฐ๊ฐ ํ์คํ ๋ฆฌ๊ฐ ๊ฐ์ง๋ ์ข ๋ฅ๊ฐ ์ฌ๋ฌ๊ฐ์ธ๋ฐ, ์ด๋ฌํ ์ ๋ณด๋ฅผ ํ๊ฐ์ง ํ ์ด๋ธ์ ๋ชจ๋ ๋๋ ๊ฒ์ด ๋ง์๊น ๊ณ ๋ฏผ์ด ๋ฉ๋๋ค.
์ด์ ์๋ JSONํ์์ผ๋ก ์ ๋์ ์ธ ์ ๋ณด์ ๋ํด์ ์ ๋ถ JSON์ผ๋ก ์ ์ฅํ๋๋ก ํ๋๋ฐ, JSON์ ํตํด ์ ์ฅํ๋ ๊ฒ์ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ธฐ๋ณธ ์๋ฆฌ์๋ ์ข ๋ฒ์ด๋๋ ๋ฐฉ์์ด๋ผ๋ ํผ๋๋ฐฑ์ ๋ค์์ต๋๋ค. ๊ทธ๋ฌ๋ฉด์๋ ์ด๋ฒ ์คํฐ๋๊ทธ๋ฃน ๋ฆฌ๋ทฐ ์๊ฐ์์๋ ์ด์ ๋ํด JSON์ผ๋ก ํ์ ๋ถ๋ค๋ ๊ณ์๋๋ฐ, ์ ๋์ ์ธ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํด์ผ ํ๊ธฐ ๋๋ฌธ์ ๋ณ๋ก ์๊ด์ด ์๋ค๊ณ ์๊ฐํ์ จ๋ค๋ ๋ถ๋ ๊ณ์ ์ ๋ฌด์์ด RDB์ ํ์ฉ์ฑ์ ๋์ผ ์ ์๋ ๋ฐฉ์์ผ์ง๊ฐ ํท๊ฐ๋ฆฌ๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ด์ ๋ํด์ ๋ฉํ ๋์ ๊ณ ๊ฒฌ์ ์ฌ์ญ๊ณ ์ถ์ต๋๋ค.