Sails.js填充嵌套关联

Dar*_*tra 49 nested associations populate node.js sails.js

我自己有一个关于Sails.js版本0.10-rc5中的关联的问题.我一直在构建一个应用程序,其中多个模型相互关联,我已到达我需要以某种方式嵌套关联的点.

有三个部分:

首先是博客文章,这是由用户编写的.在博客文章中,我想显示关联用户的信息,如用户名.现在,这里一切正常.直到下一步:我正在尝试显示与帖子相关的评论.

注释是一个单独的模型,称为Comment.每个人还有一个与之相关的作者(用户).我可以轻松地显示评论列表,但是当我想显示与评论​​相关的用户信息时,我无法弄清楚如何使用用户的信息填充评论.

在我的控制器中,我试图做这样的事情:

Post
  .findOne(req.param('id'))
  .populate('user')
  .populate('comments') // I want to populate this comment with .populate('user') or something
  .exec(function(err, post) {
    // Handle errors & render view etc.
  });
Run Code Online (Sandbox Code Playgroud)

在我的Post''show'动作中,我试图检索这样的信息(简化):

<ul> 
  <%- _.each(post.comments, function(comment) { %>
    <li>
      <%= comment.user.name %>
      <%= comment.description %>
    </li>
  <% }); %>
</ul>
Run Code Online (Sandbox Code Playgroud)

但是,comment.user.name将是未定义的.如果我尝试访问'user'属性,例如comment.user,它将显示它的ID.这告诉我,当我将评论与其他模型关联时,它不会自动将用户的信息填充到评论中.

任何理想的人都能妥善解决这个问题:)?

提前致谢!

PS

为了澄清,这就是我基本上在不同模型中建立关联的方式:

// User.js
posts: {
  collection: 'post'
},   
hours: {
  collection: 'hour'
},
comments: {
  collection: 'comment'
}

// Post.js
user: {
  model: 'user'
},
comments: {
  collection: 'comment',
  via: 'post'
}

// Comment.js
user: {
  model: 'user'
},
post: {
  model: 'post'
}
Run Code Online (Sandbox Code Playgroud)

小智 45

或者您可以使用内置的Blue Bird Promise功能来制作它.(致力于Sails@v0.10.5)

请参阅以下代码:

var _ = require('lodash');

...

Post
  .findOne(req.param('id'))
  .populate('user')
  .populate('comments')
  .then(function(post) {
    var commentUsers = User.find({
        id: _.pluck(post.comments, 'user')
          //_.pluck: Retrieves the value of a 'user' property from all elements in the post.comments collection.
      })
      .then(function(commentUsers) {
        return commentUsers;
      });
    return [post, commentUsers];
  })
  .spread(function(post, commentUsers) {
    commentUsers = _.indexBy(commentUsers, 'id');
    //_.indexBy: Creates an object composed of keys generated from the results of running each element of the collection through the given callback. The corresponding value of each key is the last element responsible for generating the key
    post.comments = _.map(post.comments, function(comment) {
      comment.user = commentUsers[comment.user];
      return comment;
    });
    res.json(post);
  })
  .catch(function(err) {
    return res.serverError(err);
  });
Run Code Online (Sandbox Code Playgroud)

一些解释:

  1. 我正在使用Lo-Dash来处理数组.有关详细信息,请参阅官方文档
  2. 注意第一"然后"功能,这些对象"[交,commentUsers]"阵列内也是"承诺"对象内的返回值.这意味着它们在首次执行时不包含值数据,直到它们获得值.因此,"传播"功能将等待动作值来继续做剩下的事情.


sgr*_*454 26

目前,没有内置的方法来填充嵌套关联.您最好的选择是使用异步来进行映射:

async.auto({

    // First get the post  
    post: function(cb) {
        Post
           .findOne(req.param('id'))
           .populate('user')
           .populate('comments')
           .exec(cb);
    },

    // Then all of the comment users, using an "in" query by
    // setting "id" criteria to an array of user IDs
    commentUsers: ['post', function(cb, results) {
        User.find({id: _.pluck(results.post.comments, 'user')}).exec(cb);
    }],

    // Map the comment users to their comments
    map: ['commentUsers', function(cb, results) {
        // Index comment users by ID
        var commentUsers = _.indexBy(results.commentUsers, 'id');
        // Get a plain object version of post & comments
        var post = results.post.toObject();
        // Map users onto comments
        post.comments = post.comments.map(function(comment) {
            comment.user = commentUsers[comment.user];
            return comment;
        });
        return cb(null, post);
    }]

}, 
   // After all the async magic is finished, return the mapped result
   // (or an error if any occurred during the async block)
   function finish(err, results) {
       if (err) {return res.serverError(err);}
       return res.json(results.map);
   }
);
Run Code Online (Sandbox Code Playgroud)

它不像嵌套人口那样漂亮(在工作中,但可能不适用于v0.10),但从好的方面来看,它实际上相当有效.

  • 不会"async.waterfall"更适合这里吗? (2认同)

Jam*_*ser 5

我为此创建了一个 NPM 模块,称为nested-pop。您可以在下面的链接中找到它。

https://www.npmjs.com/package/nested-pop

按照以下方式使用它。

var nestedPop = require('nested-pop');

User.find()
.populate('dogs')
.then(function(users) {

    return nestedPop(users, {
        dogs: [
            'breed'
        ]
    }).then(function(users) {
        return users
    }).catch(function(err) {
        throw err;
    });

}).catch(function(err) {
    throw err;
);
Run Code Online (Sandbox Code Playgroud)