ltonetwork / mongodb-rest

JSON REST server for MongoDB (using node.js)
MIT License
405 stars 143 forks source link

requests containing "fields" param fail #19

Closed raisch closed 6 years ago

raisch commented 13 years ago

Due to an attempt at line 47 of mongodb/lib/mongodb/commands/query_command.js to treat the string value you pass from req.params.options['fields'] as an object.

TypeError: Object.keys called on non-object
        at Function.keys (native)
        at [object Object].toBinary (..../node_modules/mongodb/lib/mongodb/commands/query_command.js:47:15)

Issue can be fixed by changing lines 27-33 of your /lib/rest.js from:

var test = ['limit','sort','fields','skip','hint','explain','snapshot','timeout'];

for( o in req.query ) {
  if( test.indexOf(o) >= 0 ) {
    options[o] = req.query[o];
  } 
}

to

var options = crackQueryParams(req.query);

and adding the following function:

/*
 * Iterates over expected params and if they exist in query, adds
 * them to result after type validation and conversion
 *
 * @param {Object} Query parameters extracted from uri
 * @returns {Object} Options as expected by mongodb
 *
 * @throws if a param should be a Number but fails conversion
 * @throws if a param should be a JSON string but cannot be parsed into an object
 */
function crackQueryParams(query){
  var result={},
    expectedParamTypes={
      'explain':    Boolean,
      'snapshot': Boolean,
      'timeout':   Boolean,
      'limit':        Number,
      'skip':       Number,
      'sort':       Object,
      'fields':     Object,
      'hint':       Object
    };
  for (var t in expectedParamTypes) {
    var param = (query[t]||'').toLowerCase();
    if (param) {
      switch (expectedParamTypes[t]) {
        case Boolean:{
          if ('undefined' !== typeof param) {
            if ('string' === typeof param) {
              if ('' === param) {                                     // added to query without a value, assume true
                result[t] = true;
              }
              else if ('false' === param.toLowerCase()) {      // value is literal string 'false'
                result[t] = false;
              }
            }
            else {
              result[t] = Boolean(param);
            }
          }
          break;
        }
        case Number:{
          if(isNaN(param)) {
            throw new Error('query param[' + t + ']="'+param+'" cannnot be converted into an number');
          }
          else {
            result[t]=Number(param);
          }
          break;
        }
        case Object:{
          try {
            result[t] = JSON.parse(param);
          } 
          catch (e) {
            throw new Error('query param "' + t + '" cannnot be converted into an object:' + e);
          }
          break;
        }
      }
    }
  }
  return result;
}
tdegrunt commented 13 years ago

Could you provide an example of your query? ie. what request are you running against it?

liujiahit commented 12 years ago

I just don't know how to add fields parameters to query in url.

query={"name" : "bob"}, {"name" : 1, "age" : "1"}

then encode it.

But this string will cause exception, do you know how to solve this?

alopezo commented 10 years ago

I have the same issue now (2014), and got here googling... any news?

Thanks

Minstel commented 6 years ago

@raisch @alopezo You can query in the following way: ?fields={"bar":1}