如何在sailsjs控制器中运行多个查询?

时间:2013-11-11 18:24:33

标签: orm sails.js

在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 个答案:

答案 0 :(得分: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()函数应该返回一个promise,来自Sails的标准查找器将透明地工作(只是不传递回调)。根据this other question它似乎是标准的finder的行为与Q promises不完全相同,我给出的答案应该有助于获得更加一致的行为。

More on Q and how it works in the doc !

答案 1 :(得分:9)

您也可以使用async.auto(见下文)。这里是完整的帆回复示例link

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

    }
};

答案 2 :(得分: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
          });

      });

}); 

第二种方式是使用promises(我以前没有意识到这一点)

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

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

答案 3 :(得分: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);
});