본문으로 바로가기

몽고가 성공적으로 설치되었음을 확인했다면 우리가 사용하고 있는 Javascript로 사용할 수 있게 mongoDB를 연결해보자. mongoDB는 다른 언어(C++)로 구성되어 있어 javascript와의 adapter를 통한 연결 작업이 필요하다. 우리는 mongoose를 이용할 것이다.

 

mongoDB NoSQL는 schemaless라는 장점이 있지만 mongoose는 스키마를 작성합니다. mongoDB의 자유도를 조금 제한하는 대신 좀 더 가지런하고 정렬된 형태로 정보를 받을 수 있게 됩니다.

 

여담으로, 몽구스는 ODM(obejct, document)입니다. 시퀄라이즈가 node.js 환경에서 MySQL을 JS로 사용하기 위한 ORM(object, relation을 매핑)이었다면 몽구스는 object와 document를 매핑하기 때문입니다.

 

 

 ⚡ mongoose 설치

 

npm install mongoose

 

 ⚡ connect 및 연결 에러, 끊김 핸들링

 

이건 뭐 각자 코딩하는 스타일에 달린 문제긴 합니다. models 폴더 내부에 index.js에 connect를 해주기도하고 db.js라는 파일을 새로 만들어서 connect하기도 합니다.

 

연결 주소는 mongodb://[usernmae:password@]host[:port][/[database][?options]]이다.

좀 더 정확하게는 mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]

 

import mongoose from "mongoose";
import dotenv from "dotenv";
dotenv.config();

const connect = () => {
  if (process.env.NODE_ENV !== "production") {
      mongoose.set("debug", true);
  }
  mongoose.connect(process.env.MONGO_URL, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useCreateIndex: true,
    useFindAndModify: false,
  });
};

connect();

const db = mongoose.connection;

const handleOpen = () => console.log("✅ connected to DB");
const handleError = (error) => console.log(`❌ ${error}`);

// 연결, 에러, 접속 끊김이 일어나면 콜백함수를 실행합니다.
// 연결 끊길 시 자동으로 재접속을 실행하게끔 콜백함수를 설정했습니다.
db.once("open", handleOpen);
db.on("error", handleError);
db.on("disconnected", connect);

 

로컬 환경에서 개발한다면 딱히 신경 쓸 필요 없이 다음과 같이 연결합시다.

const mongoose = require("mongoose");
mongoose
  .connect("mongodb://localhost:27017",
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useCreateIndex: true,
    useFindAndModify: false,
    dbName: "KinoProject",
  })
  .then(() => console.log(`mongoDB conn
  .catch((err) => console.error(err));

 

  로그인을 한 뒤에 사용하고 싶다면 다음과 같은 과정을 거쳐야 합니다.  만약 아이디가 없다면 다음과 같은 방법으로 만들 수 있습니다. 

use admin // admin db 사용
db.createUser({user: "root", pwd: "비밀번호", roles: ['root']})

 

  아이디를 가진 상태에서 admin db로 접속 후에 dbName을 통해 원하는 db를 사용할 수 있습니다. 

 

const mongoose = require("mongoose");

module.exports = () => {
  const connect = () => {
    if (process.env.NODE_ENV !== "production") {
      mongoose.set("debug", true);
    }
    
    // 주소, 옵션, 오류를 받습니다
    mongoose.connect(
      // 해당 로그인으로 접속합니다.
      "mongodb://root:비밀번호@localhost:27017/admin",
      {
        // 해당 DB를 생성(사용) 합니다.
        dbName: "nodejs",
        useNewUrlParser: true,
        useFindAndModify: false,
        useUnifiedTopology: true,
      },
      (error) => {
        if (error) {
          console.log("mongoDB connection Error!", error);
        } else {
          console.log("mongodb connection success!");
        }
      }
    );
  };
  
  connect();

  // 에러 발생시 에러를 로깅합니다.
  mongoose.connection.on("error", (error) => {
    console.log("mongodb connection Error!", error);
  });

  // 연결이 끊겼을시 콜백 함수를 통해 자동으로 재접속 합니다.
  mongoose.connection.on("disconnected", () => {
    console.log("mongodb disconnected!. Try connect again");
    connect()
  });

  // 작성한 스키마들을 import합니다.
  require("./comment");
  require("./user");
};

  


models 폴더 생성 후 컬렉션 작성, 스키마 정의

 

모델와 스키마를 구분해봅시다.

 

A Mongoose model is a wrapper on the Mongoose schema. 
A Mongoose schema defines the structure of the document, default values, validators, etc., whereas a Mongoose model provides an interface to the database for creating, querying, updating, deleting records, etc.

 

모델은 스키마를 감싸고 있는 것입니다. 스키마는 도큐먼트의 구조를 정의한 것입니다. 

models 폴더 내부의 각 js 파일들은 mongoDB의 컬렉션에 해당합니다. (DB - 컬렉션 - 도큐먼트으로 구조화)

import mongoose from "mongoose";

// 스키마를 만들었습니다.
const chatSchema = new mongoose.Schema({
  room: {
    type: mongoose.Schema.Types.ObjectId,
    required: true,
    ref: "Room",
    // Room 스키마를 참고(ref)하여 type에 ObjectId를 넣습니다. 이로서 관계가 성립합니다.
  },
  user: {
    type: String,
    required: true,
  },
  chat: String,
  gif: String,
  createAt: {
    type: Date,
    default: Date.now,
  },
});

// 스키마를 모델로 감싸줍니다
// model 메서드의 첫 인자는 스키마의 이름(마음대로) 두번째는 스키마
// 세번째 메서드를 줘서 DB에 실제로 보여지는 컬렉션 이름을 정의할 수 있습니다.
// 할당하지 않으면 스키마의 이름의 복수형(여기선 chats)가 컬렉션 이름이 됩니다.
const model = mongoose.model("Chat", chatSchema);

export default model;

 

외에도 default: "what", unique: true/false와 같은 정의 방법도 있습니다. 

 

 

app.js에 작성한 mongoose 연결 및 model들 연결

import connect from "./db";
import dotenv from "dotenv";
import "./models/Video";
import "./models/User";
import "./models/Comment";
import app from "./app";

dotenv.config();

// mongoDB 연결
connect();

const PORT = process.env.PORT || 4000;

const handleListening = () =>
  console.log(`✅  Listening on: http://localhost:${PORT}`);

app.listen(PORT, handleListening);

 


이제 활용해봅시다. 대개 제출 버튼을 누르면 라우터로 AJAX 요청을 보내는 코드가 있습니다.

 

 

⚡ form에서 날아온 값 DB에 추가 

 

폼을 작성한 후 POST로 날리면 controller 단에서는 해당 정보들을 req.body에서 뽑아서 User에 저장합니다. 저장은 new User와 같이 생성자를 통해 도큐먼트를 생성한 후 save() 함수를 이용합니다.

 

const User = require('../schemas/user');

router.post('/', function (req, res, next) {
  // req.body에서 input 값을 뽑아냈으면 모델에 저장합니다.
  const user = new User({
    name: req.body.name,
    age: req.body.age,
    married: req.body.married,
  });
  user.save()
    .then((result) => {
      console.log(result);
      res.status(201).json(result);
    })
    .catch((err) => {
      console.error(err);
      next(err);
    });
});

 

 

⚡ DB값을 활용해 화면에 표시하기

 

일반 페이지에서 DB를 사용해서 표시할 수도 있습니다. find(), findOne() 함수를 이용합니다. 또, 컨트롤러 단에서 DB를 사용할 때는 반드시 .then .catch를 사용해 에러도 잡고 동기적으로 일을 처리하도록 합시다. 위 작업이 다 되지도 않았는데 다음 코드를 실행하면 오류가 나기 십상입니다. 위에서 새로운 도큐먼트를 등록하는 과정도 .then .catch가 사용되었습니다.

const User = require('../schemas/user');

router.get('/', function (req, res, next) {
  User.find({})
    // User의 각 모델의 도큐먼트마다 해당 작업을 합니다.
    .then((users) => {
      // mongoose.pug에서 표시할 수 있게 users를 전달합니다.
      res.render('mongoose', { users });
    })
    .catch((err) => {
      console.error(err);
      next(err);
    });
});

 

⚡ 수정과 제거

 

update()remove()를 사용합니다. 여기서 독특한 점은 get, post와 같이 흔히 사용된 메서드가 아니라 patch와 delete가 사용된다는 점입니다.

const Comment = require('../schemas/comment');

router.patch('/:id', function (req, res, next) {
  Comment.update({ _id: req.params.id }, { comment: req.body.comment })
    .then((result) => {
      res.json(result);
    })
    .catch((err) => {
      console.error(err);
      next(err);
    });
});

router.delete('/:id', function (req, res, next) {
  Comment.remove({ _id: req.params.id })
    .then((result) => {
      res.json(result);
    })
    .catch((err) => {
      console.error(err);
      next(err);
    });
});

 


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체