太上老俊

mongoose的关联查询 :populate

mongoose关联查询从3.2版本开始支持

基本用法如下:

var studentSchema = new Schema({
    name:String,
    age:String,
    school:{
        type:Schema.Types.ObjectId,
        ref:'school'
    }
});


var schoolSchema = new Schema({
    name:String,
    students:[
        {
            type:Schema.Types.ObjectId,
            ref:"student"
        }
    ]
})


var Student = mongoose.model('student',studentSchema);

var School = mongoose.model("school",schoolSchema);


School.findOne({name:"xxx"}).populate("students","name age").exec(function(err,school){
    console.log(school);
    console.log("============")
})

//populatte中第二个参数,只返回关联表中的字段
Student.findOne({name:"xxx"}).populate("school","name").exec(function(err,student){
    console.log(student);
    console.log("===============")
})

 

总结点:

  1、schame中的ref值需要对应mongoose.model中的第一个参数,即数据库中的集合名称,否者查询失败

  2、populate(arg1,arg2)

      第一个参数对应集合中的存续关联数据的属性,若对应错误,查询成功,但关联集合只有_id返回。

      第二个参数用于过滤查询关联集合中的属性,多个属性用空格隔开,若缺失,返回关联集合的所有参数,可以传"-_id"去除返回值中的_id属性

    注:官方说明:In Mongoose >= 4.0, you can manually populate a field as well.

//官方例子
Story. findOne({ title:
/casino royale/i }). populate('author', 'name'). // only return the Persons name exec(function (err, story) { if (err) return handleError(err); console.log('The author is %s', story.author.name); // prints "The author is Ian Fleming" console.log('The authors age is %s', story.author.age); // prints "The authors age is null' });

  3、多个关联集合 

Story.
  find(...).
  populate('fans').
  populate('author').
  exec();

关于多个关联集合,若同时populate多个相同的集合,则只有最后一个产生作用

   

School.findOne({name:"xxxx"})
.populate("students","name")
.populate("students","age")
.exec(function(err,school){
    console.log(school);
    console.log("============")
})
//返回结果中只有age,没有name
//也可以写为:
populate({ path: 'students', select: 'name age' })

  

  4、关联条件查询

Story.
  find(...).
  populate({
    path: 'fans',//关联的结合
    match: { age: { $gte: 21 }},//条件
    select: 'name -_id',//去掉_id属性,选择name
    options: { limit: 5 }//分页
  }).
  exec();

  5、多级查询

var userSchema = new Schema({
  name: String,
  friends: [{ type: ObjectId, ref: 'User' }]
});

User.
  findOne({ name: 'Val' }).
  populate({
    path: 'friends',//查询我的朋友
    // Get friends of friends - populate the 'friends' array for every friend
    populate: { path: 'friends' }//查询我朋友的朋友列表
  });

  6、跨数据库查询

    

var eventSchema = new Schema({
  name: String,
  // The id of the corresponding conversation
  // Notice there's no ref here!
  conversation: ObjectId
});
var conversationSchema = new Schema({
  numMessages: Number
});

var db1 = mongoose.createConnection('localhost:27000/db1');
var db2 = mongoose.createConnection('localhost:27001/db2');

var Event = db1.model('Event', eventSchema);
var Conversation = db2.model('Conversation', conversationSchema);

//给populate的conversation指定一个model,这样就能通过model跨数据库查询
Event.
  find().
  populate({ path: 'conversation', model: Conversation }).
  exec(function(error, docs) { /* ... */ });

 

7、动态参考:假如有个用户的schema,有个关联的字段为group,group中能来自多个集合的参考,如:group可以是一个足球队、一个篮球队。。。

  

var userSchema = new Schema({
  name: String,
  connections: [{
    kind: String,
    item: { type: ObjectId, refPath: 'connections.kind' }
//connections.kind就是表示此中的关联是kind字段对应的组织
  }]
});

var organizationSchema = new Schema({ name: String, kind: String });

var User = mongoose.model('User', userSchema);
var Organization = mongoose.model('Organization', organizationSchema);

// 有一个组织{ _id: '01'), name: "Beyond", kind: 'Band' }
//有两个用户
// {_id: '02'),name: '黄家驹',
//   connections: [
//     { kind: 'User', item: '03') },
//     { kind: 'Organization', item:'01') }
//   ]
// },
// {
//   _id: '03',
//   name: '叶世荣',
//   connections: []
// }

User.
  findOne({ name: '黄家驹' }).
  populate('connections.item').//关联中的item
  exec(function(error, doc) {
    // doc.connections[0].item is a User doc
    // doc.connections[1].item is an Organization doc
  });

//总结:
//   refPath告诉mongoose,populate指向connetions.item,
// 而connetions.item又指向connetions.kind,kind最终存的是对应的model,
// kind的值可以不一样,则populate中的指向就会根据kind的值不同而改变,类似动态参数一样

8、虚拟填充:版本>4.5

  不是根据_id的关联查询,如下面的例子是关联band名字的关联查询

var PersonSchema = new Schema({
  name: String,
  band: String
});

var BandSchema = new Schema({
  name: String
});
//给BandSchme设置一个虚拟关联字段:members; BandSchema.virtual(
'members', { ref: 'Person', // 虚拟字段的model为Person localField: 'name', // 查找到Person.band的值和Band.name的值相等的项 foreignField: 'band', // // justOne用于指定,返回的members是单个数据还是一个数组集合,justOne默认为false justOne: false }); var Person = mongoose.model('Person', PersonSchema); var Band = mongoose.model('Band', BandSchema); /** * 假如有两个band:"beyond", "唐朝乐队" * 有4个Person: 黄家驹(黄家驹.band = beyond) 黄家强(黄家强.band="beyond")
* 丁武(丁武.band = "唐朝乐队") 陈磊(陈磊.band="唐朝乐队")
*/ Band.find({}).populate('members').exec(function(error, bands) {
  //这里返回的bands含有members字段,里面的值为Person的实例
});

 

以上基本上是官方文档的所有说明了,需要注意版本的不同。

  

 

posted on 2018-01-21 00:19  太上老俊  阅读(1267)  评论(0编辑  收藏

导航