Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

233
Vistas
Construct MongoDB query from GraphQL request

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

about 4 years ago · Juan Pablo Isaza
2 Respuestas
Responde la pregunta

0

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"
    }
  }
}
about 4 years ago · Juan Pablo Isaza Denunciar

0

Expanding from @Manuel Spigolon original answer, where he stated that one of the pitfalls of his implementation is that it doesn't work on nested queries and 'multiple queries into one request' which this implementation seeks to fix.

function formFilter(context:any) {
    let filter:any = {};

    let getValues = (selection:any, parentObj?:string[]) => {
        //selection = labelSelection(selection);

        selection.map((selection:any) => {
            // Check if the parentObj is defined
            if(parentObj)
                // Merge the two objects
                _.merge(filter, [...parentObj, null].reduceRight((obj, next) => {
                    if(next === null) return ({[selection.name?.value]: 1});
                    return ({[next]: obj});
                }, {}));

            // Check for a nested selection set
            if(selection.selectionSet?.selections !== undefined){
                // If the selection has a selection set, then we need to recurse
                if(!parentObj) getValues(selection.selectionSet?.selections, [selection.name.value]);

                // If the selection is nested
                else getValues(selection.selectionSet?.selections, [...parentObj, selection.name.value]);
            }
        });
    }

    // Start the recursive function
    getValues(context.operation.selectionSet.selections);

    return filter;
}

Input

{
  role(id: "61f1ccc79623d445bd2f677f") {
        name
    users {
      user_name
      _id
      permissions {
        roles
      }
    }
    permissions
  }
}

Output (JSON.stringify)

{
   "role":{
      "name":1,
      "users":{
         "user_name":1,
         "_id":1,
         "permissions":{
            "roles":1
         }
      },
      "permissions":1
   }
}
about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda