Home > database >  Construct MongoDB query from GraphQL request
Construct MongoDB query from GraphQL request

Time:01-30

Let's say we query the server with this request, we only want to get the following user's Email, My current implementation requests the whole User object from the MongoDB, which I can imagine is extremely inefficient.

GQL
{
  user(id:"34567345637456") {
    email
  }
}

How would you go about creating a MongoDB filter that would only return those Specified Fields? E.g,

JS object
{
   "email": 1
}

My current server is running Node.js, Fastify and Mercurius

CodePudding user response:

which I can imagine is extremely inefficient.

Doing this task is an advanced feature with many pitfalls. I would suggest starting building a simple extraction that read all the fields. This solution works and does not return any additional field to the client.

The pitfalls are:

  • nested queries
  • complex object composition
  • aliasing
  • multiple queries into one request

Here an example that does what you are looking for. It manages aliasing and multiple queries.

const Fastify = require('fastify')
const mercurius = require('mercurius')

const app = Fastify({ logger: true })

const schema = `
  type Query {
    select: Foo
  }

  type Foo {
    a: String
    b: String
  }
`

const resolvers = {
  Query: {
    select: async (parent, args, context, info) => {
      const currentQueryName = info.path.key

      // search the input query AST node
      const selection = info.operation.selectionSet.selections.find(
        (selection) => {
          return (
            selection.name.value === currentQueryName ||
            selection.alias.value === currentQueryName
          )
        }
      )
      
      // grab the fields requested by the user
      const project = selection.selectionSet.selections.map((selection) => {
        return selection.name.value
      })

      // do the query using the projection
      const result = {}
      project.forEach((fieldName) => {
        result[fieldName] = fieldName
      })

      return result
    },
  },
}

app.register(mercurius, {
  schema,
  resolvers,
  graphiql: true,
})

app.listen(3000)

Call it using:

query {
  one: select {
    a
  }
  two: select {
    a
    aliasMe:b
  }
}

Returns

{
  "data": {
    "one": {
      "a": "a"
    },
    "two": {
      "a": "a",
      "aliasMe": "b"
    }
  }
}
  •  Tags:  
  • Related