13

在sailsjs 中,您一次只能运行和传递一组查询数据。例如这里是我主页的控制器:

     module.exports = {

       index: function (req, res) {

        Blog.find()
        .limit(3)
        .sort('createdAt desc')
        .where({ isPublished: 1 })
        .exec(function(err, posts) {
          if (err) return next(err);
          res.view({
            layout: "homeLayout",
            posts:posts
          });    
        });  
      }

    };

我将如何从其他模型中查询数据并将其与我已经通过的博客数据一起传递给我的视图?

4

4 回答 4

10

你可以使用 Promises 来做到这一点。它实际上是一个很好的用例。我使用Q,这是Waterline(Sail 的 ORM)在幕后使用的。

您可以在下面看到一个代码示例,其中我从第一个模型中检索数据,然后,使用我检索到的数据,我查询其他模型以获取更多数据(并行),最后,我将结果发回到视图。

      SomeModel.findOne(criterias).then(function(result) {
        Q.all([
          SomeOtherModel.getSomething(result),
          YetAnotherModel.getSomethingElse(result)
        ]).spread(function(someOtherResult, yetAnotherResult) {
          var data = {
            thing: result,
            stuff: someOtherResult,
            otherthing: yetAnotherResult
          };
          return res.view(data);
        });
      }).fail(function(reason) {
        return res.view(reason);
      });

getSomething()函数应该返回一个承诺,Sails 的标准查找器将透明地工作(只是不要传递回调)。根据这个其他问题,标准查找器的行为似乎与 Q 承诺的行为不完全一样,我在那里给出的答案应该有助于获得更一致的行为。

更多关于 Q 以及它在文档中的工作原理!

于 2013-11-13T15:57:22.627 回答
9

您也可以使用 async.auto(见下文)。这是完整sails repo示例的链接。

var async = require('async'),
    _ = require('lodash');

module.exports = {


    index: function (req, res) {

        async.auto({

            // Get the blog posts
            posts: function (cb) {
                Blog.find()
                    .where({ isPublished: 1 })
                    .limit(5)
                    .sort('createdAt DESC')
                    .exec(cb);
            },


            // Get some more stuff
            // (this will happen AT THE SAME TIME as `posts` above)
            otherThings: function (cb) {
                OtherThing.find()
                    .limit(30)
                    .exec(cb);
            },


            // Get comments
            // (we'll wait until `posts` is finished first)
            comments: ['posts', function (cb, async_data) {

                // Get `posts`
                // (the second argument to cb() back in `posts`)
                // Used map to make sure posts are an array of ids and not just an object. 
                var posts = async_data.posts.map(function (item){ return item.id});

                // Get comments that whose `post_id` is equal to 
                // the id of one of the posts we found earlier
                Comment.find()
                    .where({ post_id: posts })
                    .exec(cb);
            }]

        },
        function allDone (err, async_data) {

            // If an error is passed as the first argument to cb
            // in any of the functions above, then the async block
            // will break, and this function will be called.
            if (err) return res.serverError(err);

            var posts = async_data.posts;
            var comments = async_data.comments;

            var otherThings = async_data.otherThings;

            // Fold the comments into the appropriate post
            // An in-memory join
            _.map(posts, function (post) {
                var theseComments =
                    _.where(comments, { post_id: post.id });
                post.comments = theseComments;

            });

            // Show a view using our data
            res.json({
                // layout: 'homeLayout',
                posts: posts,
                otherThings: otherThings
            });
        });

    }
};
于 2013-11-18T14:57:03.760 回答
8

我想出了一些方法来实现这一点。第一种方法是嵌套查询,例如。

Blog.find()
  .limit(30)
  .sort('createdAt desc')
  .where({ isPublished: 1 })
  .exec(function(err, posts) {

        SomeOtherModel.find()
        .limit(5)
        .sort('createdAt desc')
        .where({ isPublished: 1 })
        .exec(function(err, otherdata) {

          res.view({
            posts: posts,
            otherdata: otherdata
          });

      });

}); 

第二种方法是使用承诺(我以前不知道这一点)

 User.findOne()
.where({ id: 2 })
.then(function(user){
    var comments = Comment.find({userId: user.id}).then(function(comments){
        return comments;
    });
    return [user.id, user.friendsList, comments];
}).spread(function(userId, friendsList, comments){
    // Promises are awesome!
}).fail(function(err){
    // An error occured
})  

第三种方式(我最终选择了这个)是创建一个策略(特定于sailsjs,但是是快速中间件)

 // saved as /api/policies/recentPosts.js
 // also need to add a rule to /config/policies.js
 module.exports = function (req, res, ok) {

       Blog.find()
        .limit(3)
        .sort('createdAt desc')
        .where({ isPublished: 1 })
        .exec(function(err, footerposts) {

            res.footerposts = footerposts;
            return ok();
      });           
 };

这样做你不需要将任何东西传递给你的视图但是我不确定将数据随机添加到响应对象是否是好的做法。

于 2013-11-12T23:06:50.123 回答
5

因此,您可以通过以下方式发出 3 个请求并将其所有数据传递到您的视图中:

先安装Q

npm install q

然后使用下面的代码并将我的模型替换为您的模型:

// first import Q
var Q = require('q');

// Let's combine results of 3 queries
Q.all([
      // let's find one user with name "Pavel"
      User.findOne({name: 'Pavel'}).then(),

      // let's find one Lexus car
      Cars.findOne({brand: 'Lexus'}).then(),

      // Finally let's get the first Apple phone
      Phones.findOne({brand: 'Apple'}).then()
    ])
.spread(function (user, car, phone) {
  // Output results as json, but you can do whatever you want here
  res.json([user, car, phone]);
}).fail(function (reason) {
  // output reason of failure
  res.json(reason);
});
于 2014-05-28T19:15:06.683 回答