1

I have a function using mongoose to query my database. The connection already works. However, if I do not use actual strings, but instead string variables, the .find returns an undefined object (i.e. it doesn't find anything). Here is the code:

function getUser(obj, callback){
    console.log("obj.key: " + obj.key[0].toString() + ":" + obj.value[0].toString());
    var first = "name.first";
    console.log("first: " + first);
    var second = "nicholas";
    console.log("second: " + second);
    User.findOne({first:second}, 'name telephone address1 address2 city state zip country', function(err, user){//nothing can be found when not directly using a string!!!
        console.log("got this user: " + user.name);

    });
}

this does not work, however, if I replace the line with .find with this, it does:

User.findOne({"name.first":"nicholas"}, 'name telephone address1 address2 city state zip country', function(err, user){

I've never seen anything like this before. Normally a string is a string and it will work no matter what you do with it. Any ideas what might be wrong?

p.s.the console.logs:

obj.key: name.first:nicholas
first: name.first
second: nicholas
error at: console.log("got this user...cannot read property 'name' of null.

Sylvain Leroux
  • 50,096
  • 7
  • 103
  • 125
  • it looks like the key part of the JSON object is the problem. I can use a variable for the value part, but the key part has to be a string and not a variable for some reason. I've also tried this with a flat object (firstname instead of name.first), but I get the same result. – Nicholas Sallis May 20 '15 at 15:59

2 Answers2

1

Use the [] notation to use a variable as an object key:

var first = "name.first";
var second = "nicholas";
var query = {};
query[first] = second;
User.findOne(query, 'name telephone address1 address2 city state zip country', function(err, user){
    console.log("got this user: " + user.name);
});
JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
0

As per JavaScript object literal syntax, in the notation {first:second}, first is a property name, not a variable subject to expansion.

To quote the doc:

Object property names can be any string, including the empty string. If the property name would not be a valid JavaScript identifier, it must be enclosed in quotes. Property names that would not be valid identifiers also cannot be accessed as a dot (.) property, but can be accessed and set with the array-like notation("[]").


Given you question:

  • User.findOne({"name.first":"nicholas"}, ...) works as your property is named name.first (this is a MongoDB property using the dot notation)
  • User.findOne({first:"nicholas"}, ...) does not work as you are refering to a field named first

You may achieve the desired result by initializing your object field using []:

query = {}
query[first] = "nicholas"
//    ^^^^^
//  this is a variable
User.findOne(query, ...)

Please note as this is a recurrent need, ECMA 6 has object literal computed property keys allowing you to write something like that:

{ [first]: "nicholas" }

AFAIK, as of today this is not much supported by the major JS implementation though.

Sylvain Leroux
  • 50,096
  • 7
  • 103
  • 125
  • Cool! that actually makes a lot of sense though I have to admit that I would not have come up with that on my own. {[first]:"nicholas"} doesn't seam to work, but maybe I'm using it wrong, but creating an object as an array for the query works a charm and is exactly what I wanted to do anyway, so thanks for that :) – Nicholas Sallis May 21 '15 at 13:20