使用 Bluebird 深入填充 Sailsjs 中的对象?
Use Bluebird to deep populate objects in Sailsjs?
我有 two popular 和类似的问题,但不同之处在于那些只需要担心一个对象的深度填充关联,而我的是关于 N 个对象。
假设我定义了 3 个模型(为清楚起见省略了一些属性):
identity: 'room',
attributes: {
LocationId : { type: 'integer',
primaryKey: true,
required: true,
autoIncrement: true },
DisplayName : { type: 'string',
unique: true },
FloorId : { model: 'Floor' }
}
identity: 'floor',
attributes: {
FloorId : { type: 'integer',
primaryKey: true },
FloorName : { type: 'string' },
BuildingId : { model: 'Building' },
rooms: {collection:'room', via:'FloorId'}
}
identity: 'building',
attributes: {
BuildingId : { type: 'integer',
primaryKey: true },
BuildingName : { type: 'string' },
floors: {collection:'floor', via:'BuildingId'}
}
最终目标是拥有一个具有以下基本结构的对象数组:
[{
"LocationId": 555,
"DisplayName": 'SomeCoolName',
"Floor" : {
"FloorId": 1337,
"FloorName": '5',
"Building": {
"BuildingId": 4321,
"BuildingName": 'HQ'
}
}
}, {...}]
由于不了解 BlueBird 库 promises 以及我应该做的事情,我没有走得太远:
showWithAssetGeo: function(req, res) {
room.find( { assetCount: { '>': 0 } } )
.populate('FloorId')
.each(function(room){
var Building = Building.find({ id: _.pluck(room.FloorId, 'BuildingId') })
.then(function(Building) {return Building;});
return [room, Building];
})
.spread(function(room, Building) {
//Something to combine it all?
})
.catch (function(err) {
if (err) { res.badRequest('reason' + err); }
}
}
更新: 必须调整下面标记的答案。 Here is the final working code.
您需要确保通过调用 then 或 exec 来执行查找(每个都不会这样做)。
您似乎在尝试绘制所有楼层的地图,然后将这些承诺恢复到一个楼层。 Promise.all() 是做到这一点的方法。
试试下面的方法:
showWithAssetGeo: function(req, res) {
room.find( { assetCount: { '>': 0 } } )
.populate('FloorId')
.then(function(rooms) {
return Promise.all(rooms.map(function(room) {
return Building.findOne({id: room.FloorId.BuildingId})
.then(function(building) {
room.FloorId.building = building;
});
})
})
.then(function(deeplyPopulatedRooms) {
res.json(deeplyPopulatedRooms);
})
.catch(function(error) {
if (err) { res.badRequest('reason' + err); }
});
}
但是,提取所有可能建筑物的 ID 并对所有 ID 进行一次查找可能会更高效。但以上应该有效,并且似乎与您之前采用的方法一致。
我有 two popular 和类似的问题,但不同之处在于那些只需要担心一个对象的深度填充关联,而我的是关于 N 个对象。
假设我定义了 3 个模型(为清楚起见省略了一些属性):
identity: 'room',
attributes: {
LocationId : { type: 'integer',
primaryKey: true,
required: true,
autoIncrement: true },
DisplayName : { type: 'string',
unique: true },
FloorId : { model: 'Floor' }
}
identity: 'floor',
attributes: {
FloorId : { type: 'integer',
primaryKey: true },
FloorName : { type: 'string' },
BuildingId : { model: 'Building' },
rooms: {collection:'room', via:'FloorId'}
}
identity: 'building',
attributes: {
BuildingId : { type: 'integer',
primaryKey: true },
BuildingName : { type: 'string' },
floors: {collection:'floor', via:'BuildingId'}
}
最终目标是拥有一个具有以下基本结构的对象数组:
[{
"LocationId": 555,
"DisplayName": 'SomeCoolName',
"Floor" : {
"FloorId": 1337,
"FloorName": '5',
"Building": {
"BuildingId": 4321,
"BuildingName": 'HQ'
}
}
}, {...}]
由于不了解 BlueBird 库 promises 以及我应该做的事情,我没有走得太远:
showWithAssetGeo: function(req, res) {
room.find( { assetCount: { '>': 0 } } )
.populate('FloorId')
.each(function(room){
var Building = Building.find({ id: _.pluck(room.FloorId, 'BuildingId') })
.then(function(Building) {return Building;});
return [room, Building];
})
.spread(function(room, Building) {
//Something to combine it all?
})
.catch (function(err) {
if (err) { res.badRequest('reason' + err); }
}
}
更新: 必须调整下面标记的答案。 Here is the final working code.
您需要确保通过调用 then 或 exec 来执行查找(每个都不会这样做)。
您似乎在尝试绘制所有楼层的地图,然后将这些承诺恢复到一个楼层。 Promise.all() 是做到这一点的方法。
试试下面的方法:
showWithAssetGeo: function(req, res) {
room.find( { assetCount: { '>': 0 } } )
.populate('FloorId')
.then(function(rooms) {
return Promise.all(rooms.map(function(room) {
return Building.findOne({id: room.FloorId.BuildingId})
.then(function(building) {
room.FloorId.building = building;
});
})
})
.then(function(deeplyPopulatedRooms) {
res.json(deeplyPopulatedRooms);
})
.catch(function(error) {
if (err) { res.badRequest('reason' + err); }
});
}
但是,提取所有可能建筑物的 ID 并对所有 ID 进行一次查找可能会更高效。但以上应该有效,并且似乎与您之前采用的方法一致。