Sails.js填充嵌套的关联

我有一个关于Sails.js版本0.10-rc5的关联的问题。 我一直在build立一个应用程序,其中多个模型相互关联,我到达了一个点,我需要以某种方式来嵌套协会。

有三个部分:

首先是一个博客文章,这是由用户写的。 在博客文章中,我想显示相关用户的信息,如他们的用户名。 现在,这里一切正常。 直到下一步:我试图显示与post相关的评论。

评论是一个单独的模型,称为评论。 每个人都有一个作者(用户)与之相关联。 我可以很容易地显示评论列表,但是当我想显示与评论​​相关的用户信息时,我无法弄清楚如何用用户信息填充评论。

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

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

在我的博客的“表演”行动中,我试图检索这样的信息(简体):

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

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

任何任何理想来解决这个妥当:)?

提前致谢!

PS

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

 // 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' } 

或者您可以使用内置的蓝鸟许诺function来制作它。 (使用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); }); 

一些解释:

  1. 我正在使用Lo-Dash来处理数组。 欲了解更多详情,请参阅官方文件
  2. 注意第一个“then”函数内部的返回值,数组内的那些对象“[post,commentUsers]”也是“promise”对象。 这意味着它们在第一次执行时不包含数值数据,直到获得数值。 所以“传播”function将等待演讲的价值来继续做其余的东西。

目前,还没有内置的方式来填充嵌套关联。 你最好的select是使用asynchronous做一个映射:

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

它不如嵌套的人口(这是工作,但可能不是v0.10)漂亮,但在光明的一面,它实际上是相当有效的。

值得一提的是添加嵌套人口的请求: https : //github.com/balderdashy/waterline/pull/1052

拉请求不是合并在这一刻,但你可以使用它直接安装一个

 npm i Atlantis-Software/waterline#deepPopulate 

有了它,你可以做一些像.populate('user.comments ...)'

  sails v0.11 doesn't support _.pluck and _.indexBy use sails.util.pluck and sails.util.indexBy instead. 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:sails.util.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 = sails.util.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); } ); 

你可以使用非常干净和简单易懂的asynchronous库。 对于与post相关的每条评论,您可以根据需要使用专用任务填充许多字段,并行执行并在所有任务完成时检索结果。 最后,你只需要返回最后的结果。

 Post .findOne(req.param('id')) .populate('user') .populate('comments') // I want to populate this comment with .populate('user') or something .exec(function (err, post) { // populate each post in parallel async.each(post.comments, function (comment, callback) { // you can populate many elements or only one... var populateTasks = { user: function (cb) { User.findOne({ id: comment.user }) .exec(function (err, result) { cb(err, result); }); } } async.parallel(populateTasks, function (err, resultSet) { if (err) { return next(err); } post.comments = resultSet.user; // finish callback(); }); }, function (err) {// final callback if (err) { return next(err); } return res.json(post); }); }); 

我为这个被称为嵌套stream行音乐创build了一个NPM模块。 你可以在下面的链接find它。

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