Population은 문서의 지정된 경로를 다른 컬렉션의 문서로 자동 교체하는 프로세스입니다.
단일 문서, 여러 문서, 일반 개체, 여러 일반 개체 또는 쿼리에서 반환된 모든 개체를 채울 수 있습니다.
예시 코드는 예전에 공부할때 사용했던 영화 리뷰 등록 프로젝트로 사용하였음.
const mongoose = require('mongoose'); // Erase if already required
var reviewSchema = new mongoose.Schema({
comment: String,
score: {
type: Number,
min: 1,
max: 5
},
target: {
type: mongoose.Schema.Types.ObjectId,
ref: "Movie"
},
targetstr: {
type: String,
},
targetCd: {
type: String,
},
createdAt: {
type: Date,
default: Date.now()
}
});
module.exports = mongoose.model('Review', reviewSchema);
const mongoose = require('mongoose');
var movieSchema = new mongoose.Schema({
movieCd: String,
movieNm: String,
movieNmEn: String,
prdtYear: String,
openDt: String,
typeNm: String,
prdtstatNm: String,
nationAlt: String,
genreAlt: String,
repNationNm: String,
repGenreNm: String,
directors: [{ peopleNm: String }],
companys: [{ companyCd: String, companyNm: String }],
});
module.exports = mongoose.model('Movie', movieSchema);
const mongoose = require("mongoose");
const Movie = require("./model/movie");
const Review = require("./model/review");
const url = "mongodb+srv://mongoDB_URI";
!async function () {
await mongoose.connect(url, { dbName: "example" });
let reviews = await Review.find({}).populate("target");
//let reviews = await Review.find({}).populate("", "movieNm repGenreNm");
// path 다음 인자에 select도 사용 가능함.
console.log(reviews);
}();
{
_id: new ObjectId("62e74a33b6b80650d6d56174"),
comment: '더빙 너무 잘됐어요',
score: 4,
target: {
_id: new ObjectId("62e1da422e7c1c96838d3cb6"),
movieCd: '20226107',
movieNm: '극장판 도라에몽: 진구의 우주소전쟁 리틀스타워즈 2021',
movieNmEn: 'Doraemon the Movie: Nobita’s Little Star Wars 2021',
prdtYear: '2021',
openDt: '20220803',
typeNm: '장편',
prdtStatNm: '개봉예정',
nationAlt: '일본',
genreAlt: '애니메이션',
repNationNm: '일본',
repGenreNm: '애니메이션',
directors: [Array],
companys: []
},
targetCd: '20226107',
createdAt: 2022-08-01T03: 32: 48.248Z,
__v: 0
}
populate를 그냥 사용하게 되면 기본적으로 대상 ref모델의 _id로 매칭이 되는데 이것을 변경하고 싶다면 virtual을 사용해야 한다.
예시 코드는 예전에 공부할때 사용했던 영화 리뷰 등록 프로젝트로 사용하였음.
const mongoose = require('mongoose'); // Erase if already required
var reviewSchema = new mongoose.Schema({
...
});
// virtual을 이용해서 populate용 가상 변수를 설정할 수 있음.
reviewSchema.virtual("vtTargetCd", {
localField: "targetCd", // 비교할 로컬 필드
ref: "Movie", // 비교해야하는 컬렉션
foreignField: "movieCd", // 비교해야하는 컬렉션의 필드
// justOne: true // 한개의 행만 받아와야 할때 사용
})
module.exports = mongoose.model('Review', reviewSchema);
const mongoose = require("mongoose");
const Movie = require("./model/movie");
const Review = require("./model/review");
const url = "mongodb+srv://mongoDB_URI";
!async function () {
await mongoose.connect(url, { dbName: "example" });
let reviews = await Review.find({}).populate("vtTargetCd").lean();
console.dir(reviews, { depth: 3 });
}();
{
_id: new ObjectId("62e74a33b6b80650d6d56174"),
comment: '더빙 너무 잘됐어요',
score: 4,
target: new ObjectId("62e1da422e7c1c96838d3cb6"),
targetCd: '20226107',
createdAt: 2022-08-01T03:32:48.248Z,
__v: 0,
vtTargetCd: [
{
_id: [ObjectId],
movieCd: '20226107',
movieNm: '극장판 도라에몽: 진구의 우주소전쟁 리틀스타워즈 2021',
movieNmEn: 'Doraemon the Movie: Nobita’s Little Star Wars 2021',
prdtYear: '2021',
openDt: '20220803',
typeNm: '장편',
prdtStatNm: '개봉예정',
nationAlt: '일본',
genreAlt: '애니메이션',
repNationNm: '일본',
repGenreNm: '애니메이션',
directors: [Array],
companys: []
}
]
}
populate는 체이닝으로 여러번 사용이 가능하다.
populate에 match를 사용하여 조건을 걸어줄 수 있다.
populate에 select를 사용하여 원하는 필드의 값을 가져오거나 제외할 수 있다.
예시 코드는 학원에서 팀 프로젝트로 만들었던 가게 예약 시스템 서버단 코드 일부분을 발췌
import mongoose from 'mongoose';
let rstrSchema = new mongoose.Schema({
RSTR_ID: Number,
RSTR_NM: String,
BSNS_STATM_BZCND_NM: String,
})
rstrSchema.virtual("rstrImg", { // 가게 이미지 가져오기
localField: "RSTR_NM",
ref: "rstr_img",
foreignField: "RSTR_NM",
justOne: true
});
rstrSchema.virtual("getMenu", { // 가게 메뉴 가져오기
localField: "RSTR_ID",
ref: "menu",
foreignField: "RSTR_ID",
});
export default mongoose.model('rstr', rstrSchema, "rstr");
import express from 'express';
import RSTR from '../model/rstr.js' // mongo 식당 기본 정보
import RSTR_OPRT from '../model/rstr_oprt.js' // 식당 운영 정보
import RSTR_IMG from '../model/rstr_img.js' // 식당 이미지 정보
import MENU from '../model/menu.js' // 식당 메뉴 정보
const router = express.Router();
router
...
// 메뉴 검색 해서 식당 가져오기
.get("/getSearchMenu", async (req, res) => {
console.log(req.query);
// 해당 메뉴가 있는 식당의 ID를 가져와서 중복 제거하고 가게 정보 가져오기
MENU.find({ MENU_NM: { $regex: req.query.menu } }).distinct("RSTR_ID").then((result) => {
// 중복 제거한 식당ID 값으로 메뉴 불러오기
RSTR.find({ RSTR_ID: result }).populate({
path: "getMenu",
match: { MENU_NM: { $regex: req.query.menu } },
select: "-_id -RSTR_ID MENU_NM",
}).populate("rstrImg").lean().then((result) => {
res.status(200).json({ result: true, length: result.length, datas: result });
})
}).catch((err) => {
res.status(501).json({ result: false, message: err });
});
})
export default router;
{
"_id": "633fa0e0590e2837ff5ba360",
"RSTR_ID": 1243,
"RSTR_NM": "왕자관",
"RSTR_RDNMADR": "광주광역시 동구 충장로 101-6",
"RSTR_LNNO_ADRES": "광주광역시 동구 충장로1가 8-2",
"RSTR_LA": "35.1472485",
"RSTR_LO": "126.9182939",
"RSTR_TELNO": "062-222-3344",
"BSNS_STATM_BZCND_NM": "중국식",
"BSNS_LCNC_NM": "일반음식점",
"RSTR_INTRCN_CONT": "\"왕자관\"은 광주광역시 동구에 있는 맛집으로, 가장 가까운 지하철역은 문화전당역(구도청)입니다. 50년 이상의 전통을 자랑합니다.",
"getMenu": [
{
"MENU_NM": "유니짜장"
},
{
"MENU_NM": "간짜장"
}
],
"rstrImg": {
"_id": "633fa198590e2837ff5bbaf3",
"RSTR_ID": 1243,
"RSTR_NM": "왕자관",
"AREA_NM": "광주광역시 동구",
"RSTR_IMG_URL": "https://ukcooyocdlvo8099722.cdn.ntruss.com/public_data/2021-12/restaurant/875538_1565136201.jpg"
}
}