在使用 mongoose 时,通过一个外键与另一张表建立关联
mongoose官网地址
语法
Query.populate(path, [select], [model], [match], [options])
|
尝试中发现 select 默认会填充 _id。
model: Model,可选,指定关联字段的 model,如果没有指定就会使用Schema的ref。
match: Object,可选,指定附加的查询条件。
options:Object,可选,指定附加的其他查询选项,如排序以及条数限制等等。
基本使用
数据模型
创建三个Schema和Model。
var mongoose = require('mongoose'); mongoose.Promise = require('bluebird'); mongoose.connect('mongodb://localhost/population');
var Schema = mongoose.Schema; var userSchema = new Schema({ name: String, age: Number, posts: [{ type: Schema.Types.ObjectId, ref: 'post' }], comments: [{ type: Schema.Types.ObjectId, ref: 'comment' }] }); var User = mongoose.model('user', userSchema);
var postSchema = new Schema({ title: String, content: String, author: { type: Schema.Types.ObjectId, ref: 'user' }, comments: [{ type: Schema.Types.ObjectId, ref: 'comment' }] }); var Post = mongoose.model('post', postSchema);
var commentSchema = new Schema({ content: String, author: { type: Schema.Types.ObjectId, ref: 'user' } }) var Comment = mongoose.model('comment', commentSchema);
exports.User = User; exports.Post = Post; exports.Comment = Comment;
|
在上述的例子中,创建了三个 Models:User,Post,Comment。
User 的属性 posts,对应是一个 ObjectId 的数组。ref表示关联Post(注意: 被关联的model的 type 必须是 ObjectId, Number, String, 和 Buffer 才有效)。
Post的属性 poster 和 comments 分别关联User和Comment。
Comment的属性 post 和 commenter 分别关联Post和User。
三个 Models 的关系:一个 user–has many–>post。一个 post–has one–>user,has many–>comment。一个 comment–has one–>post 和 user。
注: ref 对应是在connection中注册过的model。
var User = mongoose.model('user', userSchema); ... author: {type: Schema.Types.ObjectId, ref: 'user'}
|
填充User的posts字段:
User.find() .populate('posts', 'title', null, {sort: { title: -1 }}) .exec(function(err, docs) { onsole.log(docs[0].posts[0].title); });
User.findOne({name: 'luajin'}) .populate({path: 'posts', select: { title: 1 }, options: {sort: { title: -1 }}}) .exec(function(err, doc) { console.log(doc.posts[0].title); });
User.find() .populate('posts', 'title', null, {sort: { title: -1 }}) .exec(function(err, docs) { console.log(docs[0].posts[0].title); });
User.findOne({name: 'luajin'}) .populate({path: 'posts', select: { title: 1 }, options: {sort: { title: -1 }}}) .exec(function(err, doc) { console.log(doc.posts[0].title); });
|
填充多个字段
假如,我们要填充 Post 中的 author 和 comments,且填充 author 的 name 和 age,还有 comments 的 content; 不填充 author 和 comments 的 _id。
Post.findOne({ 'title': 'test' }).populate('author comments', 'name age content -_id').exec() .then(function(post) { console.log(post); }).catch(function(reason) { console.log(reason); });
Post.findOne({ 'title': 'test' }).populate([ { path: 'author', select: 'name age -_id' }, { path: 'comments', select: 'content -_id' }]).exec() .then(function(post) { console.log(post); }).catch(function(reason) { console.log(reason); });
{ _id: 584a030733604a156a4f6600, author: { name: 'Tom', age: 19 }, title: 'test', content: 'wakaka', __v: 1, comments: [ { content: 'walala' } ] }
|