[MongoDB] Mongoose(몽구스) populate 사용해서 다른 collection의 documents ObjectId 참조하기


Mongoose(몽구스)에서 populate을 사용하면 다른 Collection에 있는 documents의 ObjectId를 이용하여 documents 참조가 가능하다.

조금 더 보충하자면 MongoDB 자체에서 Documents 마다 자동으로 만들어주는 고유값인 ObjectId가 있는데 다른 Collection에서 populate 메서드를 사용해서 하나의 Documents에 또 다른 Documents의 정보들을 같이 담을 수 있게 해준다.


example)

User.js (Model)

const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const saltRounds = 10;
const jwt = require("jsonwebtoken");

const userSchema = mongoose.Schema({
     email: {
     type: String,
     unique: 1,
    },
    name: {
    type: String,
     },
    nickname: {
    type: String,
    unique: 1,
    },
    password: {
    type: String,
    minlength: 6,
    },
    eventAgreement: {
     type: Boolean,
    },
    createdAt: {
     type: Number,
    },
    google: {
     type: String,
    },
    github: {
     type: String,
    },
    profile: {
     type: String,
    },
    token: {
     type: String,
    },
    tokenExp: {
    type: Number,
    },
    });

.... 생략


ShoppingBasket.js (Model)

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const shoppingBasketSchema = mongoose.Schema(
{
writer: {
type: Schema.Types.ObjectId,
ref: "User",
},
userFrom: {
type: String,
},
title: {
type: String,
maxlength: 50,
},
description: {
type: String,
},
duration: {
type: String,
},
thumbnail: {
type: String,
},
genre: {
type: String,
},
filePath: {
type: String,
unique: 1,
},
cost: {
type: Number,
},
},
{ timestamps: true }
);

const ShoppingBasket = mongoose.model("ShoppingBasket", shoppingBasketSchema);

module.exports = { ShoppingBasket };


일단 Mongoose(몽구스) 스키마 모델에 아래 문장을 작성해야지 User Collection에 있는 documents ObjdectId를 참조하여 저장하도록 세팅이 된다.

type: Schema.Types.ObjectId,
ref: "User",


그런 후 api 요청할때 Json 내부에 writer의 값으로 User 모델의 ObjectId값을 전달해 준다.(ObjectId는 _id로 표기된다.)

const shoppingBasketData = {
writer: video.writer._id,
userFrom,
title: video.title,
description: video.description,
duration: video.duration,
thumbnail: video.thumbnail,
genre: video.genre,
filePath: video.filePath,
cost: video.cost,
};

const handleShoppingBasket = () => {
axios
.post("/api/shoppingBasket/addShoppingBasket", shoppingBasketData)
.then((response) => {
console.log(response);
if (response.data.success) {
alert("장바구니에 담았습니다.");
} else {
if (response.data.err.keyPattern.filePath) {
return alert("이미 장바구니에 담겼습니다.");
}
alert("오류가 발생했습니다. 나중에 시도해주세요.");
}
});
};


그 후 전달받은 내용을 저장한다. (save 부분)

const express = require("express");
const router = express.Router();
const { ShoppingBasket } = require("../models/ShoppingBasket");

router.post("/addShoppingBasket", (req, res) => {
// 장바구니 목록에 추가
const shoppingBasket = new ShoppingBasket(req.body);
console.log(req.body);

shoppingBasket.save((err, shoppingBasket) => {
if (err) return res.json({ success: false, err });
return res.status(200).json({
success: true,
});
});
});

router.post("/getShoppingBasketList", (req, res) => {
//로그인한 사용자 장바구니 목록
ShoppingBasket.find({ userFrom: req.body.loginUser })
.populate("writer")
.exec((err, shoppingbaskets) => {
if (err) return res.status(400).send(err);
res.status(200).json({ success: true, shoppingbaskets });
});
});

module.exports = router;


나중에 /getShoppingBasketList 로 ShoppingBasket Collection에서 목록을 가져올때 스키마 모델에서 작성했던, 참조하도록 했던 스키마 모델의 명칭을 populate 메서드의 인자로 주게되면 ShoppingBasket 목록을 가져오면서 참조된 User 모델도 같이 결과 값으로 받을 수 있다.


아래의 결과를 보면 리스트를 받아왔는데 해당 documents안에 Writer가 있을 수 있는 이유는 이전에 백엔드로 데이터를 전달할 때 writer에  ObjectId를 식별자로 전달했기 때문이다. 그래서 Video 모델에서 데이터를 가져오지만 User documents가 같이 출력되는것을 확인할 수 있다.



요약하면

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const shoppingBasketSchema = mongoose.Schema(
{
writer: {
type: Schema.Types.ObjectId,
ref: "User",
},

    ... 생략

위 코드에서 처럼 스키마 모델을 만들때 특정 모델의 documents의 ObejctId를 받을 수 있도록 작성하고, 데이터를 저장한 뒤에 몽구스의 populate를 사용하여 스키마 모델에 ObjectId 로 참조되어있는  Documents를 같이 호출할 수 있게 된다.


댓글