帆/水线:如何检索关系中的关系?

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

所以,我有以下三种模式:

用户型号:

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(....)我得到用户和相关的Pets。 我怎样才能得到每个宠物相关的疫苗? 在官方文档中我没有find有关这方面的参考资料。

我也遇到了这个问题,据我所知,嵌套关联查询不是内置到sails(截至这篇文章)。

你可以使用承诺为你处理嵌套的人口,但是如果你填充很多层次的话,这可能会变得相当多毛。

就像是:

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

这是sails.js广泛讨论的主题,实际上有一个开放的请求,增加了这个function的大部分。 看看https://github.com/balderdashy/waterline/pull/1052

虽然Kevin Le的答案是正确的,但它可能会变得有点混乱,因为你在循环内执行asynchronous函数。 当然,它是有效的,但是假设你想在所有的宠物和疫苗完成后返回给用户 – 你怎么做?

有几种方法可以解决这个问题。 一个是使用asynchronous库 ,它提供了一堆util函数来处理asynchronous代码。 该库已包含在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); }); }); 

蓝鸟承诺也是解决这个问题的另一种方法,这也是风帆的一部分。 它可能比以前更高效,因为它只需要一个数据库请求即可获取所有疫苗。 另一方面更难以阅读…

 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); });