zoukankan      html  css  js  c++  java
  • 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的实例
    });

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

      

  • 相关阅读:
    webpack进阶(二)
    webpack的loader和plugin的区别
    接口和面向接口编程
    设计原则与编程技巧汇总
    W3C的盒子模型和IE的盒子模型
    React的组件
    React的路由react-router
    三种编程命名规则:驼峰命名法,帕斯卡命名法,匈牙利命名法
    gulp 构建 demo
    antd 表单的两种校验方式
  • 原文地址:https://www.cnblogs.com/laojun/p/8322448.html
Copyright © 2011-2022 走看看