Mongoose Populate

語言: CN / TW / HK

這是我參與11月更文挑戰的第2天,活動詳情檢視:2021最後一次更文挑戰

在 Mongoose 中,Populate 允許您引用其他集合中的文件。其類似於 SQL 中的左外部連線,但區別在於 Populate 發生在 Node.js 應用程式中,而不是在資料庫伺服器上。Mongoose 在引擎下執行單獨的查詢以載入引用的文件。

Populate 基礎

假設你有兩個 Mongoose 模型MoviePersonMovie 文件有一個 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() 方法,允許您在一行中載入電影及其相應的 directoractors

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'