Mongoose & Node.js에서 Populate 사용하기

00_8_3·2021년 1월 7일
4

Mongoose & Node.js에서 Populate 사용하기

Population 이란??

Population는 문서의 경로를 다른 컬렉션의 실제 문서로 자동으로 바꾸는 방법입니다. 예를들어 문서 사용자 ID를 해당 사용자의 데이터로 바꿉니다. Mongoose는 우리를 도울 수있는 Population을 가지고 있습니다. 우리는 우리의 스키마에 ref를 정의하고 mongoose는 해당 ref를 사용하여 다른 컬렉션의 문서를 찾습니다.

population의 몇 가지 사항

  • pupulate가 문서에 없다면 필드는 null이다.
  • 문서 배열의 경우 문서가 없으면 빈 배열이다.
  • 여러 필드를 populate 하기위해 populate를 묶을 수 있습니다.
  • 두 개의 populate이 동일한 필드를 populate하면 두 번째 populate가 첫 번째 populate를 재정의합니다.

시작 전 3개의 스키마

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

const UserSchema = new Schema({
   name: String,
   email: String,
   blogs: [{ 
      type: mongoose.Schema.Types.ObjectId,
      ref: "Blog"
   }]
});

const BlogSchema = new Schema({
   title: String,
   user: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User"
   },
   body: String,
   comments: [{
      type: mongoose.Schema.Types.ObjectId,
      ref: "Comment"
   }]
})

const CommentSchema = new Schema({
   user: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User"
   },
   blog: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Blog"
   },
   body: String
})


const User = mongoose.model("Author", UserSchema);
const Blog = mongoose.model("Blog", BlogSchema);
const Comment = mongoose.model("Comment", CommentSchema);

module.exports = {User, Blog, Comment}

Populate 작동 ?

const User = require("path/to/userSchema");

User
   .findOne({_id: userId })
   .populate("blogs") // key to populate
   .then(user => {
      res.json(user); 
   });

/*
OUTPUT:
 {
    _id: userid, // obviously it will be id generated by mongo
    name: "john doe",
    email: "john@email.com",
    blogs: [
        {
            _id: blogid, 
            title: "how to do nothing",
            body: "Interesting matter in 11111the blog...",
            comments: [commentId_1, commentId_2]
        }
    ]
 }
*/

Nested Populate in a document

User
   .findOne({_id: userId })
   .populate({
      path: "blogs", // populate blogs
      populate: {
         path: "comments" // in blogs, populate comments
      }
   })
   .then(user => {
      res.json(user); 
   });

/*
OUTPUT:
 {
    _id: userid, // obviously it will be id generated by mongo
    name: "john doe",
    email: "john@email.com",
    blogs: [
        {
            _id: blogid, 
            title: "how to do nothing",
            body: "Interesting matter in the blog...",
            comments: [
                {
                    user: userId,
                    blog: blogId,
                    body: "your blog is awesome !"
                }
            ]
        }
    ]
 }
*/

populating 동안 특정 필드를 선택하려는 경우 select 키를 사용하여 개체 내부의 필드를 지정할 수 있습니다.

// simple populate
User
   .findOne({_id: userId })
   .populate("blogs", { name: 1 }) // get name only

// nested populate
User
   .findOne({_id: userId})
   .populate({
      path: "blogs",
      populate: {
         path: "comments",
         select: { body: 1 } // 1
      }
   })

Populate After Save ?

드물지만 가끔 DB에 저장 후 population을 하고 싶을 수 있습니다.
예를 들어, 새 댓글을 작성하고 저장하지만 응답과 함께 보낼 때 사용자 ID 대신 사용자 정보를 추가 합니다.

const Comment = require("/path/to/commentSchema");

let newComment = new Comment({
   user: userId,
   blog: blogId,
   body: "this is a new comment"
});

newComment.save().then(result => {
   Comment
      .populate(newComment, { path: "user" })
      .then(comment => {

         res.json({
            message: "Comment added",
            comment
         });

      })
})

/*
OUTPUT: Comment
   {
      message: "Comment added"
      user: {
         _id: userid,
         name: "test test",
         email: "test@email.com",
         blogs: [blogId_1, blogId_2]
      },
      blog: blogId,
      body: "this is a new comment"
   }
*/

1개의 댓글