docs: function(req, options) {
      var query = {};
      var queries = [];
      options = options || {};
  
      // Need to make sure these are strings, they get parsed to int later
      options.skip = options.skip ? options.skip.toString() : options.skip;
      options.limit = options.limit ? options.limit.toString() : options.limit;
  
      // Reserved Params
      var created = req.query.created || {}; // accepts both s and ms
      var updated = req.query.updated || {}; // accepts both s and ms
      var sortBy = options.sortParam || req.query.sort || this.sortParam;
      var orderBy = options.sortOrder || req.query.order || this.sortOrder;
      var skip = options.skip || req.query.skip || req.query.offset || this.skip;
      var limit = options.limit || req.query.limit || req.query.count || this.limit;
      skip = _.parseInt(skip) || 0;
      limit = _.parseInt(limit) || 0;
  
      var page = _.parseInt(req.query.page);
      if (page > 0) {
        // IMPORTANT! `page` starts at 1
        // if `page` is specified, we override `skip`
        // calculate skip based on page and limit
        // lets assume limit is 100
        // page 1 is skip 0
        // page 2 is skip 100
        // etc...
        skip = (page - 1) * limit;
      }
  
      // Date Range params
      var createdQuery = this._buildTimestampQuery(created);
      var updatedQuery = this._buildTimestampQuery(updated);
  
      if (!_.isEmpty(createdQuery)) {
        queries.push({
          created: createdQuery
        });
      }
      if (!_.isEmpty(updatedQuery)) {
        queries.push({
          updated: updatedQuery
        });
      }
  
      // Filter params
      var queryParams = _.assign(_.result(this, 'queryParams'), {
        'user_id': 'string'
      });
      if (_.isObject(options.queryParams)) {
        _.assign(queryParams, options.queryParams);
      }
      var filterParams = _.pick(req.query, _.keys(queryParams));
      var logicalOperator = '$' + (req.query.logical || 'and').toLowerCase().replace(/[@\s]/g, '');
  
      _.forEach(filterParams, function(val, key) {
        // If value is all, ignore this param
        if (val === 'all') {
          return;
        }
  
        // Make sure val is a string (should usually be from express)
        if (!_.isString(val)) {
          val = val.toString();
        }
  
        // Support `,` as `$or` for each param
        var vals = val.split(',');
  
        // No value, ignore this param
        if (vals.length === 0) {
          return;
        }
  
        // The built query filter
        var filter = {};
  
        // Get param type
        var type = queryParams[key];
  
        // Deal with different param types
        if (type === 'string') {
          // strings and objectid
          // no transformation
        } else if (type === 'regex') {
          // regex case insensitive and escaping special characters
          vals = _.map(vals, function(v) {
            return {
              '$regex': Mixins.escapeRegExp(v),
              '$options': 'i'
            };
          });
        } else if (type === 'integer') {
          // integers
          vals = _.map(vals, function(v) {
            return _.parseInt(v);
          });
        } else if (type === 'float') {
          // floats
          vals = _.map(vals, function(v) {
            return parseFloat(v);
          });
        } else {
          // invalid or unknown type
          return;
        }
  
        // If there is only one val, no need to use `$or`
        if (vals.length === 1) {
          filter[key] = vals[0];
        } else {
          var orExpr = [];
          _.forEach(vals, function(orVal) {
            var orClause = {};
            orClause[key] = orVal;
            orExpr.push(orClause);
          });
          filter['$or'] = orExpr;
        }
  
        queries.push(filter);
      });
  
      // Combine the query
      if (queries.length > 0) {
        query[logicalOperator] = queries;
      }
  
      // Options
      // Sort/Order/Limit/Skip
      var sortOptions = [
        [sortBy, orderBy]
      ];
  
      var result = {
        'query': query,
        'sort': sortOptions,
        'limit': limit,
        'skip': skip
      };
  
      debug.info(
        '#parseQueryString with req.query: %s and result: %s',
        JSON.stringify(req.query),
        JSON.stringify(result)
      );
      return result;
    }