Viewing Data via GraphQL

Testing with getUser Query

🙋 Need help? Ask an expert now!

Bonus - getUser Client-defined Query

Let's run this query from doc/, Get User:

query getUser {
  getUser(item_query: "{\"full_name\": \"John Public\"}") {

The schema is in src/relay-queries/user/get-user-query.js. item_query is a GraphQLString argument that we convert into a JS Object and pass into the src/db-handlers/user/user-fetch.js fetchByKey to use as the filter calling basicFind database query wrapper. So, we execute User.findOne() mongoose function with the exact filter coded on the GraphQL client. As explained before, this can be used in a "trusted expert client" or a "test" mode and should not part of a public API.

Run the query and take a look at these debug log statements:

<timestamp> debug:   response: {"primary_locale":"en","_id":"1Eg6d1aFL8s7","full_name":"John Public","username":"john01","primary_email":"","created_at":",<date-time>Z","updated_at":"<date-time>Z","__v":0}
<timestamp> debug:   response obj keys: $__,isNew,errors,_doc,$init
<timestamp> debug:   response obj keys-to: primary_locale,_id,full_name,username,primary_email,created_at,updated_at,__v

The debug above comes from this code (see src/relay-resolvers/user-resolver.js resolveGetUser):

  const response = await fetchByKey(queryVal, {}, viewer, info);
  logger.debug(`  response: ` + JSON.stringify(response));
  logger.debug(`  response obj keys: ` + Object.keys(response));
  logger.debug(`  response obj keys-to: ` + Object.keys(response.toObject()));
  return response;

response is the object that came from mongoose findOne(), and its keys (or properties that the object contains) are $__,isNew,errors,_doc,$init - not what we'd expect by looking at the debug output of the response itself via JSON.stringify():

{"primary_locale":"en","_id":"1Eg6d1aFL8s7","full_name":"John Public","username":"john01","primary_email":"","created_at":",<date-time>Z","updated_at":"<date-time>Z","__v":0}

Converting the response object toObject() produces the "correct" keys, as seen on the last debug line: primary_locale,_id,full_name,username,primary_email,created_at,updated_at,__v

So, the mongoose query result is a special object. We hardly ever encounter difficulties processing those objects in regular JS code as most of the time JS functions see the data content of it vs. whatever else mongoose plugs in into there. E.g., JSON.stringify() or the GraphQL engine don't require the toObject() conversion.

On rare occasions, however, 3rd party packages may fail processing mongoose objects as data. In those cases, use toObject(). Just something to keep in the back of your mind when working with mongoose. Generally, mongoose is helping structuring the application, so, we're keeping it around in the demo project.

Use lean() Before exec()

Adding lean() before exec() in mongoose queries turns off the mongoose special object functionality. As you probably guessed, the functionality drives mongoose-specific model and schema-related stuff such as defaulting and validation. So, without getting into details, if all you need is to extract data vs. retrieve, analyze and update - mongoose objects are useless and can be turned off via lean().

It is recommended using lean() on queries that return many Documents to help performance by bypassing mongoose object wrapper logic that it applies to each retrieved Document. If you run into performance issues and exhausted optimization on the database side - use lean() on large volume queries. Although, you would likely benefit from the mentioned earlier batching. So, all things considered, lean() may not yield you much on the large schema of things. If your queries return lots of records from the database to the logic server (the one that uses mongoose) - you may have a serious design problem in the overall application.

This completes our GraphQL Data Serving chapter! Let's get on to mutations - there won't be much new stuff, an easy topic to learn after all the knowledge you've already gained to this point

Edit Me on GitHub!