---
# System prepended metadata

title: ' Day 18 - Mongoose - Populate'
tags: [MongoDB, node.js, Node.js 直播班-2024春季班]

---

# 🏅 Day 18 - Mongoose - Populate

Mongoose 有提供 `populate()` 方法並搭配在 schema 設定 ref 關聯，就可以將其他 collection 的資料關聯到目前在操作的 collection

以作業設計稿貼文為例，貼文除了貼文內容、圖片、貼文建立時間，也會需要使用者的資料來記錄該則貼文是哪位使用者發布的
舉例：
```javascript=
const mongoose = require('mongoose');

// 使用者 Schema、Model
const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: [true, '名字未填寫']
  },
  email: {
    type: String,
    required: [true, 'Email 未填寫'],
    select: false
  },
  photo: {
    type: String,
    default: ''
  }
}, { versionKey: false });
const User = mongoose.model('User', userSchema);

// 貼文 Schema、Model
const postSchema = new mongoose.Schema({
  user: {  
    type: mongoose.Schema.ObjectId, // users collection 的 _id
    ref: 'User'                     // 使用者的 Model 名稱
  },
  content: {
    type: String,
    required: [true, '貼文內容未填寫']
  },
  image: {
    type: String,
    default: ''
  },
  createdAt: {
    type: Date,
    default: Date.now
  },
  likes: {
    type: Number,
    default: ''
  }
}, { versionKey: false });
const Post = mongoose.model('Post', postSchema);
```
> Post 要關聯到 User 需在 schema 的 `user` 欄位設定 `ref` 告訴 Mongoose 關聯資料時要使用哪個 Model

接下來就可以使用 `populate()` 加入相關設定，就可以在取得 Post 資料時依據 Schema 的設定取得 User 的 collection 資料
大致如下：
```javascript=
Post.find()
  .populate({ path: 'user', select: 'name' })
```
取得 Post 資料時：
- `path` 設定為有關聯到 User 的屬性 `user`，就會關聯到 User 的 collection 並找出符合該 id 的資料
- `select` 可以指定要取出該資料的哪個欄位，以上方範例來說就會取出 `name` 欄位。
  使用空格間隔可以取出多個欄位，像是：`select: 'name photo'`，就會取出 `name` 和 `photo` 欄位

### 參考資源

- [Mongoose: Query Population](https://mongoosejs.com/docs/populate.html)
- [Mongoose: Schema ref](https://mongoosejs.com/docs/api/schematype.html#SchemaType.prototype.ref())

題目(回報作業)
---
延續上方範例，貼文下方的按讚 `likes` 通常會需要知道是哪位使用者按讚的，請嘗試調整貼文的 Schema，讓 `likes` 關聯使用者，當取出貼文資料時可以關聯使用者，並取出使用者的名字與圖片資料

完整下方程式碼（補上 `...` 的部分）

```javascript=
const mongoose = require('mongoose');

// 使用者 Schema、Model
const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: [true, '名字未填寫']
  },
  email: {
    type: String,
    required: [true, 'Email 未填寫'],
    select: false
  },
  photo: {
    type: String,
    default: ''
  }
}, { versionKey: false });
const User = mongoose.model('User', userSchema);

// 貼文 Schema、Model
const postSchema = new mongoose.Schema({
  user: {  
    type: mongoose.Schema.ObjectId, 
    ref: 'User'                     
  },
  content: {
    type: String,
    required: [true, '貼文內容未填寫']
  },
  image: {
    type: String,
    default: ''
  },
  createdAt: {
    type: Date,
    default: Date.now
  },
  likes: [{
    type: mongoose.Schema.ObjectId, 
    ref: 'User'
      }],
}, { versionKey: false });
const Post = mongoose.model('Post', postSchema);

// 取得貼文資料
Post.find()
  .populate({ path: 'user', select: 'name photo' });
  
```



