【问题标题】:Sails/Waterline: How to retrieve relations inside a relation?Sails/Waterline:如何在关系中检索关系?
【发布时间】:2016-08-27 04:36:24
【问题描述】:

我需要检索一个对象并获取关系和嵌套关系。

所以,我有以下三个模型:

用户模型:

module.exports = {

  attributes: {
    name: {
      type: 'string'
    },
    pets: {
      collection: 'pet',
      via: 'owner',
    }
}

宠物模型:

module.exports = {
  attributes: {
    name: {
      type: 'string'
    },
    owner: {
      model: 'user'
    },
    vaccines: {
      collection: 'vaccine',
      via: 'pet',
    }
}

疫苗型号:

module.exports = {
  attributes: {
    name: {
      type: 'string'
    },
    pet: {
      model: 'pet'
    }
}

打电话给User.findOne(name: 'everton').populate('pets').exec(....) 我得到了用户和相关的宠物。我怎样才能获得与每只宠物相关的疫苗?我在官方文档中没有找到关于这个的参考资料。

【问题讨论】:

    标签: node.js sails.js waterline


    【解决方案1】:

    我也遇到过这个问题,据我所知,嵌套关联查询还没有内置到 Sails 中(截至本文为止)。

    您可以使用 Promise 为您处理嵌套填充,但如果您填充多个级别,这可能会变得相当麻烦。

    类似:

    User.findOne(name: 'everton')
      .populate('pets')
      .then(function(user) {
        user.pets.forEach(function (pet) {
          //load pet's vaccines
        });
      });
    

    这在sails.js 上已成为广泛讨论的话题,实际上有一个开放的拉取请求添加了该功能的大部分内容。查看https://github.com/balderdashy/waterline/pull/1052

    【讨论】:

    • 谢谢@Kevin!好吧,我将按照您指示的方式实施。当他们最终将这个功能添加到框架中时,我会更新。
    【解决方案2】:

    虽然 Kevin Le 的答案是正确的,但它可能会有点混乱,因为您是在循环内执行异步函数。当然可以,但是假设您想在完成后将所有宠物和疫苗归还给用户 - 您如何做到这一点?

    有几种方法可以解决这个问题。一种是使用async library,它提供了一堆实用函数来处理异步代码。该库已包含在sails 中,默认情况下您可以在全局范围内使用它。

     User.findOneByName('TestUser')
       .populate('pets')
       .then(function (user) {
    
         var pets = user.pets;
    
         // async.each() will perform a for each loop and execute
         // a fallback after the last iteration is finished
         async.each(pets, function (pet, cb) {
    
           Vaccine.find({pet: pet.id})
             .then(function(vaccines){
    
               // I didn't find a way to reuse the attribute name
               pet.connectedVaccines = vaccines;
    
               cb();
             })
    
         }, function(){
           // this callback will be executed once all vaccines are received 
           return res.json(user);
         });
       });
    

    有另一种方法可以通过 bluebird promises 解决这个问题,这也是风帆的一部分。它可能比前一个性能更高,因为它只需一个数据库请求即可获取所有疫苗。另一方面,它更难阅读......

    User.findOneByName('TestUser')
      .populate('pets')
      .then(function (user) {
    
        var pets = user.pets,
            petsIds = [];
    
        // to avoid looping over the async function 
        // all pet ids get collected...
        pets.forEach(function(pet){
          petsIds.push(pet.id);
        });
    
        // ... to get all vaccines with one db call 
        var vaccines = Vaccine.find({pet: petsIds})
          .then(function(vaccines){
            return vaccines;
          });
    
        // with bluebird this array...
        return [user, vaccines];
      })
    
      //... will be passed here as soon as the vaccines are finished loading
      .spread(function(user, vaccines){
    
        // for the same output as before the vaccines get attached to 
        // the according pet object
        user.pets.forEach(function(pet){
    
          // as seen above the attribute name can't get used 
          // to store the data
          pet.connectedVaccines = vaccines.filter(function(vaccine){
            return vaccine.pet == pet.id;
          });
        });
    
        // then the user with all nested data can get returned
        return res.json(user);
    
      });
    

    【讨论】:

    • 谢谢@Simon,我也会试试这个方法
    猜你喜欢
    • 2017-01-01
    • 1970-01-01
    • 2014-12-06
    • 2020-08-20
    • 2013-09-28
    • 2016-01-09
    • 2019-08-24
    • 1970-01-01
    • 2013-07-15
    相关资源
    最近更新 更多