Sails/Waterline: 如何在关系中检索关系?
Sails/Waterline: How to retrieve relations inside a relation?
我需要检索对象并获取关系和嵌套关系。
所以,我有以下三个模型:
用户模型:
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(....)
我得到了用户和关联的宠物。我怎样才能为每只只宠物接种相关疫苗?我在官方文档中没有找到关于这个的参考资料。
我也 运行 研究过这个问题,据我所知,嵌套关联查询还没有内置到 sails 中(截至目前 post)。
您可以使用 promises 为您处理嵌套填充,但如果填充多个级别,这可能会变得相当棘手。
类似于:
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 Le 的答案是正确的,但它可能会变得有点混乱,因为您是在循环内执行异步函数。当然可以,但是假设您希望 return 用户在完成后拥有所有宠物和疫苗 - 您该怎么做?
有几种方法可以解决这个问题。一种是使用 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);
});
});
有一种替代方法可以使用蓝鸟承诺来解决此问题,这也是风帆的一部分。它可能比前一个性能更高,因为它只需要一个数据库请求就可以获取所有疫苗。另一方面,它更难阅读...
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);
});
我需要检索对象并获取关系和嵌套关系。
所以,我有以下三个模型:
用户模型:
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(....)
我得到了用户和关联的宠物。我怎样才能为每只只宠物接种相关疫苗?我在官方文档中没有找到关于这个的参考资料。
我也 运行 研究过这个问题,据我所知,嵌套关联查询还没有内置到 sails 中(截至目前 post)。
您可以使用 promises 为您处理嵌套填充,但如果填充多个级别,这可能会变得相当棘手。
类似于:
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 Le 的答案是正确的,但它可能会变得有点混乱,因为您是在循环内执行异步函数。当然可以,但是假设您希望 return 用户在完成后拥有所有宠物和疫苗 - 您该怎么做?
有几种方法可以解决这个问题。一种是使用 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);
});
});
有一种替代方法可以使用蓝鸟承诺来解决此问题,这也是风帆的一部分。它可能比前一个性能更高,因为它只需要一个数据库请求就可以获取所有疫苗。另一方面,它更难阅读...
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);
});