Search code examples
node.jsmongodbsails.jswaterlinesails-mongo

Combined search in sails js


I have game collection:

{
  "name": "Play RoadRash",
  "version": "1.0.0",
  "icon": "image-md-two-thirds.png",
  "id": "6dc41c3fa0e7"
}

and platform collection:

{
  "name": "PlayStation",
  "version": "7",
  "icon": "playstation.jpg",
  "id": "55eaf322f1a16"
}

I'm trying to create a search query who searches in both collection based on name parameters. Does anyone have any idea how to search on multiple collection in sails waterline?


Solution

  • We've wrote a controller with full-text search within all models. All what it does is search within all models and their attributes by q parameter from request. Here is the full code of this controller:

    var _ = require('lodash');
    var Promise = require('bluebird');
    
    module.exports = {
      index: function (req, res) {
        var models = [];
    
        if (!req.param('q')) {
          return res.badRequest(null, null, 'You should specify a "q" parameter!');
        }
    
        var q = req.param('q');
    
        if (req.param('model')) {
          var modelStr = req.param('model').toString().toLowerCase();
    
          if (!(modelStr in sails.models)) {
            return res.badRequest(null, null, 'Cannot find model: ' + modelStr);
          }
    
          models.push({name: modelStr, model: sails.models[modelStr]});
        } else {
          _.forEach(sails.models, function (model, modelStr) {
            models.push({name: modelStr, model: model});
          });
        }
    
        Promise.map(models, function (modelObj) {
          var model = modelObj.model;
          var modelStr = modelObj.name;
          var where = _.transform(model.definition, function (result, val, key) {
            result.or.push(_.set({}, key, {contains: q}));
          }, {or: []});
    
          return model
            .find(where)
            .then(function (queryRes) {
              var resObj = {};
              resObj[modelStr] = queryRes;
              return Promise.resolve(resObj)
            });
        })
          .then(function (searchRes) {
            return _.transform(searchRes, function (result, val) {
              result = _.merge(result, val);
            }, {});
          })
          .then(res.ok)
          .catch(res.serverError)
      }
    };
    

    You can just copy-paste it in your api/controllers/SearchController.js and that's it. It still need to refactor this code, but it works.