【问题标题】:Use Bluebird to deep populate objects in Sailsjs?使用 Bluebird 在 Sailsjs 中深度填充对象?
【发布时间】:2015-12-12 05:10:11
【问题描述】:

我有 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.

【问题讨论】:

  • 我几乎肯定我应该使用 .map() 而不是 .each()。我获取 Building 对象的回调不需要以顺序方式完成,并且会减慢一切。对吗?

标签: promise sails.js waterline bluebird


【解决方案1】:

您需要确保通过调用 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 进行一次查找可能会更高效。但上述方法应该可行,并且似乎与您之前采用的方法一致。

【讨论】:

    猜你喜欢
    • 2016-06-27
    • 1970-01-01
    • 2017-04-08
    • 2017-09-15
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 2019-09-01
    • 1970-01-01
    相关资源
    最近更新 更多