Mongoose Populate
這是我參與11月更文挑戰的第2天,活動詳情檢視:2021最後一次更文挑戰
在 Mongoose 中,Populate 允許您引用其他集合中的文件。其類似於 SQL 中的左外部連線,但區別在於 Populate 發生在 Node.js 應用程式中,而不是在資料庫伺服器上。Mongoose 在引擎下執行單獨的查詢以載入引用的文件。
Populate 基礎
假設你有兩個 Mongoose 模型:Movie
和 Person
。Movie
文件有一個 director
和一系列 actors
。
js
const Person = mongoose.model('Person', mongoose.Schema({
name: String
}))
// ref 告訴 Mongoose Populate 要查詢的模型
const Movie = mongoose.model('Movie', mongoose.Schema({
title: String,
director: {
type: mongoose.ObjectId,
ref: 'Person'
},
actors: [{
type: mongoose.ObjectId,
ref: 'Person'
}]
}))
Mongoose 查詢有一個 populate()
方法,允許您在一行中載入電影及其相應的 director
和 actors
:
js
const people = await Person.create([
{ name: 'James Cameron' },
{ name: 'Arnold Schwarzenegger' },
{ name: 'Linda Hamilton' }
])
await Movie.create({
title: 'Terminator 2',
director: people[0]._id,
actors: [people[1]._id, people[2]._id]
})
// 只加載電影導演
let movie = await Movie.findOne().populate('director')
console.log(movie.director.name) // 'James Cameron'
console.log(movie.actors[0].name) // undefined
// 載入導演和演員
movie = await Movie.findOne().populate(['director', 'actors'])
console.log(movie.director.name) // 'James Cameron'
console.log(movie.actors[0].name) // 'Arnold Schwarzenegger'
console.log(movie.actors[1].name) // 'Linda Hamilton'
注意:Mongoose 文件上也有一個
populate()
方法,詳細可以檢視文件。這裡需要注意的是,6.x 已移除文件上document.execPopulate()
。populate
現在返回一個 Promise,其不再是可連結。
所以,以下方法將不在適用:
js
movie = await Movie.findOne().populate('director').populate('actors')
您應將舊的連結寫法進行替換:
```js await doc.populate('path1').populate('path2').execPopulate() // 替換為 await doc.populate(['path1', 'path2'])
await doc.populate('path1', 'select1').populate('path2', 'select2').execPopulate() // 替換為 await doc.populate([{path: 'path1', select: 'select1'}, {path: 'path2', select: 'select2'}]) ```
其他案例
如果您正在 populate
單個文件,而引用的文件不存在,Mongoose 會將 populate 的屬性設定為 null
。
js
await Person.deleteOne({ name: 'James Cameron' })
const movie = await Movie.findOne().populate('director')
console.log(movie.director) // null
如果您正在 populate
一個數組,而其中一個引用的文件不存在,Mongoose 將在預設情況下從陣列中過濾該值,並返回一個較短的陣列。您可以使用 retainNullValues
選項覆蓋此選項。
js
await Person.deleteOne({ name: 'Arnold Schwarzenegger' })
let movie = await Movie.findOne().populate('actors')
console.log(movie.actors.length) // 1
console.log(movie.actors[0].name) // 'Linda Hamilton'
// 設定 retainNullValues 選項,為陣列中缺少的文件插入 null
movie = await Movie.findOne().populate({
path: 'actors',
options: { retainNullValues: true }
})
console.log(movie.actors.length) // 2
console.log(movie.actors[0]) // null
console.log(movie.actors[1].name) // 'Linda Hamilton'