函数Mongoose的populate()可以带表查询,即引用它在另一个集合中的文档。Populate()可以自动替换文档中的指定字段,替换的内容是从其他集合中获取的。refs在创建Model时,可以为Model中存放其他集合_id的字段设置ref选项。ref选项告诉Mongoose在使用populate()填充时使用哪个模型。constauthorSchema=newSchema({name:String,age:Number,story:{type:Schema.Types.ObjectId,ref:'Story'}friends:[{type:Schema.Types.ObjectId,ref:'User'}]});letAuthor=mongoose.model('Author',authorSchema);在上面的例子中,Author模型的friends字段被设置为ObjectId数组。ref选项告诉Mongoose在填充时使用User模型。friends中存储的所有_id必须是User模型中文档的_id。ObjectId、Number、String和Buffer都可以用作refs。但最好使用ObjectId。创建文档时,保存refs字段和保存普通属性一样,只是将_id的值赋给它。letauthor=newAuthor({name:'dora',age:18,story:story._id//直接赋值故事的_id});等待作者。保存();populate(path,select)populatedocumentletauthor=awaitAuthor.findOne({name:'dora'}).populate('story');author.story//{...}从中检索到的文档的填充故事字段Story表不再是原来的_id,而是被指定的文档所取代。该文档由另一个查询从数据库返回。refs数组返回存储相应_id的文档数组。没有关联文档如果没有关联文档,则返回值为null,即author.story为null;如果该字段是一个数组,则返回[]一个空数组,即author.friends是[]。letauthor=awaitAuthor.findOne({name:'dora'}).populate('friends');author.friends//[]返回字段选择如果只需要填写文档中的部分字段,可以传递给populate()的第二个参数,参数form是返回字段字符串,同Query.prototype.select()。letauthor=awaitAuthor.findOne({name:'dora'}).populate('story','title-_id');author.story//{title:...}只返回标题字段author.story.content//null其余字段为null填充多个字段letauthor=awaitAuthor.findOne({name:'dora'}).populate('story').populate('friends');如果同一个字段populate()两次,只有最后一次生效。populate({objParam})objParam:path:需要填充的字段。populate:多级填充。select:从populate的文档中选择返回的字段。模型:填充的关联模型。如果未指定,populate将根据架构中定义的ref字段中的名称查找模型。可以指定跨数据库模型。match:填充表连接查询的条件。如果满足条件,则将_id替换为文档,如果不满足条件,则将_id替换为null。选项:填充查询的选项。排序:排序。limit:限制数量。多级填充//查询好友的friendsAuthor.findOne({name:'dora'}).populate({path:'friends',populate:{path:'friends'}});cross-databasepopulation跨数据库不能直接通过schema中的ref选项填充,但是可以通过objParam中的model选项显式指定一个跨数据库模型。leteventSchema=newSchema({name:String,conversation:ObjectId//注意,这里没有指定ref!});letconversationSchema=newSchema({numMessages:Number});letdb1=mongoose.createConnection('localhost:27000/db1');letdb2=mongoose.createConnection('localhost:27001/db2');//不同数据库的ModelletsEvent=db1.model('Event',eventSchema);letConversation=db2.model('Conversation',conversationSchema);//显示指定的modelletdoc=awaitEvent.find().populate({path:'conversation',model:Conversation})通过refPath动态引用的ModelMongoose也可以用于同一个存储的_id字段跨多个不同集合查询人口。//用于存储评论的架构。用户可以对博客文章或作品发表评论。constcommentSchema=newSchema({body:{type:String,required:true},on:{type:Schema.Types.ObjectId,required:true,refPath:'onModel'},onModel:{type:String,required:true,enum:['BlogPost','Product']}});constProduct=mongoose.model('Product',newSchema({name:String}));constBlogPost=mongoose.model('BlogPost',新架构({标题:字符串}));constComment=mongoose.model('评论',commentSchema);refPath选项比ref更复杂。如果ref只是一个字符串,Mongoose将查询相同的模型以获取填充的子文档。相反,使用refPath,您可以配置用于每个不同文档的模型。constbook=awaitProduct.create({name:'LaughterField'});constblog=awaitBlogPost.create({title:'笑场经典语录,犀利句子,直击人心'});//两个指定不同评论来源的评论数据constcommentOnBook=awaitComment.create({body:'Bravo',on:book._id,onModel:'Product'});constcommentOnBlog=awaitComment.create({body:'先笑后说,笑后听我诉说心里话。',on:blog._id,onModel:'BlogPost'});constcomments=awaitComment.find().populate('on');comments[0].on.name;//“笑声”评论[1].on.title;//“笑话领域的经典名言...”当然,commentSchema中也可以定义单独的blogPost和product字段,分别存放_id和对应的ref选项。但是,这不利于业务扩展。比如在后续业务中加入用户对歌曲或电影的评论,则需要在schema中加入更多的相关字段。每个字段都需要一个populate()查询。使用refPath意味着无论commentSchema可以指向多少个Model,联合查询只需要一个populate()。
