No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Repaso - Creando el tipo Estudiante

11/25
Recursos

Aportes 47

Preguntas 5

Ordenar por:

Los aportes, preguntas y respuestas son vitales para aprender en comunidad. Regístrate o inicia sesión para participar.

Mi solución al desafío:

Implemento los mutation deleteCourse y deleteStudent que requieren un ID y devuelven en este caso un string indicando si se realizó o no la operación de borrado de la DB.

schema.graphql

type Mutation {
  "Crea un nuevo curso"
  createCourse(input: CourseInput): Course
  "Edita un curso"
  editCourse(id: ID!, input: CourseEditInput): Course
  "Elimina un curso"
  deleteCourse(id: ID!): String
  "Crea un nuevo estudiante"
  createStudent(input: StudentInput): Student
  "Edita un estudiante"
  editStudent(id: ID!, input: StudentEditInput): Student
  "Elimina un estudiante"
  deleteStudent(id: ID!): String
}

mutations.js

deleteCourse: async (root, { id }) => {
    let db, info;
    try {
      db = await connectDb();
      info = await db.collection('courses').deleteOne({
        _id: ObjectID(id)
      });
    } catch (error) {
      console.error(error);
    }
    return info.deletedCount
      ? `El curso con id ${id} fue eliminado exitosamente.`
      : 'No existe el curso con el id indicado';
  },

Para seleccionar multiples definiciones de la misma palabra como el profe le hace:

  1. Selecciona la palabra a editar
  2. Ctrl + d para seleccionar las próximas occurencias de esa palabra y editarlas al mismo tiempo (sin tener que ir a seleccionarlas una por una)

Referencia: Keyboard shortcuts

Por si alguno/a no sabia se pueden ir poniendo multiples consultas y ejecutando de a una 😄

Reto resuelto:

Me parece super genial que haya repaso en este curso. Algo bueno para imitar en los demas cursos.

de acuerdo con Jecshan Castillo, adicional mente si están haciendo todo en las nuevas versiones mongodb y usan mongo atlas me toco hacerlo así para que retornara la actualización del documento:

editCourse: async (root, { id, input }) => {
        let db
        let course

        try {
            db = await connectDb()
            course = await db.collection('courses').findOneAndUpdate(
                { _id: ObjectID(id) },
                { $set: input },
                { new : true, returnOriginal: false }
            )
        } catch (error) {
            console.error(error)
        }
        return course.value
    }

Schema

    "Elimina un Estudiante"
  deleteStudent(_id: ID!): String
    "Eliminar un Curso"
  deleteCourse(_id: ID!): String,

Resolvers

deleteStudent: async (root, { _id }) => {
      const id = await mongoDb.delete('courses', _id);
      return `Curso con Id: ${id} eliminado`;
    }

También les comparto la manera en como me conecto a Mongo, pienso que es la manera más limpia que la que hace el profesor.

const { MongoClient, ObjectId } = require('mongodb');
const { config } = require('../config');

const USER = encodeURIComponent(config.dbUser);
const PASSWORD = encodeURIComponent(config.dbPassword);
const DB_NAME = config.dbName;

const MONGO_URI = `mongodb+srv://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}/${DB_NAME}?retryWrites=true&w=majority`;

class MongoLib {
  constructor() {
    this.client = new MongoClient(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });
    this.dbName = DB_NAME;
  }

  connect() {
    if (!MongoLib.connection) {
      MongoLib.connection = new Promise((resolve, reject) => {
        this.client.connect(err => {
          if (err) {
            reject(err);
          }
          console.log('Connected succesfully to mongo');
          resolve(this.client.db(this.dbName));
        });
      });
    }
    return MongoLib.connection;
  }

  getAll(collection) {
    return this.connect().then(db => {
      return db
        .collection(collection)
        .find()
        .toArray();
    });
  }

  get(collection, id) {
    return this.connect().then(db => {
      return db
        .collection(collection)
        .findOne({ _id: ObjectId(id) });
    })
  }

  create(collection, data) {
    return this.connect()
      .then(db => {
        return db
        .collection(collection).insertOne(data);
    })
      .then(result => result.insertedId);
  }

  updated(collection, id, data) {
    return this.connect()
      .then(db => {
        return db
          .collection(collection)
          .updateOne({ _id: ObjectId(id) }, { $set: data }, { upsert: true });
      })
      .then(result => result.updsertdId || id);
  }

  delete(collection, id) {
    return this.connect()
      .then(db => {
        return db
          .collection(collection)
          .deleteOne({ _id: ObjectId(id) })
      })
      .then(() => id);
  }
}

module.exports = MongoLib;

schema

"Delete course"
  deleteCourse(_id: ID!): Course

"Delete student"
  deleteStudent(_id: ID!): Student

mutation

deleteCourse: async (root, { _id }) => {
    let db;
    let course;
    try {
      db = await connectDB();
      course = db.collection('courses').findOne({ _id: ObjectID(_id) });
      await db.collection('courses').deleteOne({ _id: ObjectID(_id) });
    } catch (error) {
      console.error(error);
    }
    return course;
  },

  deleteStudent: async (root, { _id }) => {
    let db;
    let student;
    try {
      db = await connectDB();
      student = db.collection('students').findOne({ _id: ObjectID(_id) });
      await db.collection('students').deleteOne({ _id: ObjectID(_id) });
    } catch (error) {
      console.error(error);
    }
    return student;
  }

Seguí una resolución simple:

Mutation Type:

Mutation Resolver:

Result:

Comparto mis soluciones al reto

deleteCourse: async (root, { id }) => {
    let info
    try {
      const db = await connectDB()
      // MongoDB al eliminar un documento, retorna un objeto con información del resultado del proceso, sin embargo, no retorna el documento eliminado
      info = await db.collection('courses').deleteOne({ _id: ObjectId(id) })
    } catch (error) {
      console.error(error)
    }
    console.log(info)
    return info.deletedCount ? `Curso con id ${id} eliminado satisfactoriante` : `No existe el curso con el id ${id} indicado`
  },

Este es otro enfoque

deleteStudent: async (root, { id }) => {
    let student
    try {
      const db = await connectDB()
      // Consulto primero el documento para devolverlo como resultado de la eliminación, esto puede ser interesante en Clientes que deseén notificar a sus usuarios de que datos se eleminó
      student = db.collection('students').findOne({ _id: ObjectId(id) })
      // Elimino el documento
      await db.collection('students').deleteOne({ _id: ObjectId(id) })
    } catch (error) {
      console.error(error)
    }
    return student
  }

Mi approach, yo utilizo el findOneAndDelete() y retorno un custom type con un Boolean que resuelve se se ha borrado o no y la entidad borrada

Schema.graphql

module.exports = {
.
.
.
type DeleteStudentOut{
    status: Boolean
    entity: Student
}
type DeleteCourseOut{
    status: Boolean
    entity: Course
}

type Mutation {
.
.
.
"Eliminar un curso"
    deleteCourse(_id: ID!): DeleteCourseOut
 "Elimina un estudiante"
    deleteStudent(_id: ID!): DeleteStudentOut
}

Mutations.js

module.exports = {
.
.
.
 deleteCourse: async (root, {_id}) => {
        let db, flag
        try {
            db = await connectDB()
            flag = await db.collection('cursos').findOneAndDelete({_id: ObjectID(_id)})
        } catch (error) {
            console.error(error)
        }
        return {status:flag.lastErrorObject.n, entity:flag.value}
    },
 deleteStudent: async (root, {_id}) => {
        let db, flag
        try {
            db = await connectDB()
            flag = await db.collection('estudiantes').findOneAndDelete({_id: ObjectID(_id)})
        } catch (error) {
            console.error(error)
        }
        return {status:flag.lastErrorObject.n, entity:flag.value}
    }
}
{
  "errors": [
    {
      "message": "Field \"createStudent\" of type \"Student\" must have a selection of subfields. Did you mean \"createStudent { ... }\"?",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ]
}```

si alguien me puede ayudar con este error al crear estudiante

Esta es mi solución. Creé un nuevo Type que corresponde a lo que devuelve la función deleteOne, según la documentación de mongo.

type DeleteResponse {
    acknowledged: Boolean
    deletedCount: Int
}

type Mutation {
    "Eliminar curso"
    deleteCourse(_id: ID!): DeleteResponse
    "Eliminar estudiante"
    deleteStudent(_id: ID!): DeleteResponse
}

Y finalmetne el Resolver:

deleteCourse: async (root, { _id }) => {
    let db, resp
    try {
      db = await connectDB();
      resp = await db
        .collection("courses")
        .deleteOne({ _id: ObjectId(_id) });
    } catch (error) {
      console.error(error);
    }
    return resp;
  },
  deleteStudent: async (root, { _id }) => {
    let db, resp
    try {
      db = await connectDB();
      resp= await db
        .collection("students")
        .deleteOne({ _id: ObjectId(_id) });
    } catch (error) {
      console.error(error);
    }
    return resp;
  }

queries.js

deleteStudent: async (root, args) => {
    let db;
    let student = {};
    try {
      db = await connectDB();
      student = await db
        .collection('students')
        .deleteOne({ _id: ObjectID(args.id) });
      console.log(student);
    } catch (err) {
      console.error(err);
    }
    return student;
  },

schema.graphql

type Query {
  "Return all courses"
  getCourses: [Course]
  "Return one course"
  getCourse(id: ID!): Course
  "Return all students"
  getStudents: [Student]
  "Return one student"
  getStudent(id: ID!): Student
  "Delete one course"
  deleteCourse(id: ID!): Course
  "Delete one student"
  deleteStudent(id: ID!): Student
}

Yo recomiendo usar findOneAndUpdate en lugar de hacer 2 requests a mongodb
findOneAndUpdate retorna el documento en la propiedad value, a loq ue quedaría:
students.value

Reto resuelto:
schema.graphql

    "Eliminar un curso"
    deleteCourse(_id: ID!): String

    "Eliminar un estudiante"
    deleteStudent(_id: ID!): String

mutations.js

deleteCourse: async (root, { _id }) => {
        let db;
        try {
            db = await connectDb();
            await db.collection('courses').deleteOne({ _id: ObjectID(_id) });
        } catch (error) {
            console.error(error);
        }
        return `Se elimino el curso ${_id}`;
    },
deleteStudent: async (root, { _id }) => {
        let db;
        try {
            db = await connectDb();
            await db.collection('students').deleteOne({ _id: ObjectID(_id) });
        } catch (error) {
            console.error(error);
        }
        return `Se elimino el alumno ${_id}`;
    },
 deleteStudent: async(root, {_id}) =>{
        let db
        let stateDelete
        try {
            db = await connectDb()
            stateDelete =  await db.collection('students').deleteOne(
                {_id: ObjectId(_id)}
            )
        } catch (error) {
            console.error(error)
        }
        return stateDelete
    }

En mutation type

deleteStudent(_id:ID!): DeleteRequest

Esquema DeleteRequest

type DeleteRequest{
    acknowledged: Boolean
    deletedCount: Int
}

Y lo mismo para courses.

Aporte al reto


,
    deleteCourse: async (root, { _id }) => {
        let db
        let course
        try {
            db = await connectDb()
            await db.collection('courses').deleteOne({ _id: ObjectID(_id) })
            course = await db.collection('courses').findOne({ _id: ObjectID(_id) })
        } catch (error) {
            console.error(error);
        }
        return course
    },
    deleteStudent: async (root, { _id }) => {
        let db
        let student
        try {
            db = await connectDb()
            await db.collection('students').deleteOne({ _id: ObjectID(_id) })
            student = await db.collection('students').findOne({ _id: ObjectID(_id) })
        } catch (error) {
            console.error(error);
        }
        return student
    }

Y el mutation.

type Mutation {
    "Crear un curso"
    createCourse(input: CourseInput!): Course
    "Editar un curso"
    editCourse(_id: ID!, input: CourseEditInput): Course
    "Crear un Estudiante"
    createStudent(input: StudentInput!): Student
    "Editar un Estudiante"
    editStudent(_id: ID!, input: StudentEditInput): Student
    "Elimina un curso"
    deleteCourse(_id: ID!): Course
    "Elimina un estudiante"
    deleteStudent(_id: ID!): Student
}

Mutations

schema

result

Yo utilize mongose para crear la base de datos y cree schemas y me ahorre mucho código jeje

https://mongoosejs.com/docs/index.html

const { Schema, model } = require("mongoose");

const CourseSchema = Schema({
  title: {
    type: String,
    require: [true, "The title is required"],
    unique: true,
  },
  description: { type: String, require: [true, "The description is required"] },
  teacher: { type: String },
  topic: { type: String },
});
module.exports = model("Course", CourseSchema);```
--- mutations

deleteCourse: async (root, { _id }) => {
    let db;
    let course;
    try {
      db = await connectDb();
      course = await db.collection("courses").findOne({ _id: ObjectId(_id) });
      await db.collection("courses").deleteOne({ _id: ObjectId(_id) });
    } catch (error) {
      console.error(error);
    }
    console.log(course);
    return course;
  },
  deleteStudent: async (root, { _id }) => {
    let db;
    let student;

    try {
      db = await connectDb();
      student = await db.collection("students").findOne({ _id: ObjectId(_id) });
      await db.collection("students").deleteOne({ _id: ObjectId(_id) });
    } catch (error) {
      console.error(error);
    }
    return student;
  },

My solution:

schema:

"Eliminar un curso"
  deleteCourse(_id: ID!): String
"Eliminar un estudiante"
  deleteStudent(_id: ID!): String

mutation:

deleteCourse: async (root, { _id }) => {
    let db;
    let info;
    try {
      db = await connectDB();
      info = await db.collection("courses").deleteOne({ _id: ObjectId(_id) });
      if (info.deletedCount) {
        return `Curso con ${_id} eliminado`;
      }
      return "No se encontro curso con el ID indicado";
    } catch (error) {
      console.error(error);
    }
  },

  deleteStudent: async (root, { _id }) => {
    let db;
    let info;
    try {
      db = await connectDB();
      info = await db.collection("students").deleteOne({ _id: ObjectId(_id) });
      if (info.deletedCount) {
        return `Estudiante con ${_id} eliminado`;
      }
      return "No se encontro estudiante con el ID indicado";
    } catch (error) {
      console.error(error);
    }
  },

Reto logrado:

Repaso - Creando el tipo Estudiante

Agregamos al schema.graphql:

type Course {
    _id: ID!
    title: String!
    teacher: String
    description: String!
    topic: String
}

type Student {
    _id: ID!
    name: String!
    email: String!
}

type Query {
    "Devuelve todos los cursos"
    getCourses: [Course]
    "Devuelve un curso"
    getCourse(id: ID!): Course
    "Devuelve todos los estudiantes"
    getStudents: [Student]
    "Devuelve un estudiante"
    getStudent(id: ID!): Student
}

input CourseInput {
    title: String!
    teacher: String
    description: String!
    topic: String
}

input CourseEditInput {
    title: String
    teacher: String
    description: String
    topic: String
}

input StudentInput {
    name: String!
    email: String!
}

input StudentEditInput {
    name: String
    email: String
}

type Mutation {
    "Crea un curso"
    createCourse(input: CourseInput!): Course
    "Edita un curso"
    editCourse(_id: ID!, input: CourseEditInput): Course
    "Elimina un curso"
    deleteCourse(_id: ID!): String
    "Crea un estudiante"
    createStudent(input: StudentInput!): Student
    "Edita un estudiante"
    editStudent(_id: ID!, input: StudentEditInput): Student
    "Elimina un estudiante"
    deleteStudent(_id: ID!): String
}

Modificamos queries.js:

const connectDb = require('./db')
const { ObjectId } = require('mongodb')

module.exports = {
    getCourses: async () => {
        let db
        let courses = []
        try {
            db = await connectDb()
            courses = await db.collection('courses').find().toArray() //*Devuelve todos los cursos
        } catch (error) {
            console.console.error(error);
        }
        return courses
    },
    getCourse: async (root, { id }) => {
        let db
        let course
        try {
            db = await connectDb()
            course = await db.collection('courses').findOne({ _id: ObjectId(id) })
        } catch (error) {
            console.console.error(error);
        }
        return course
    },
    getStudents: async () => {
        let db
        let students = []
        try {
            db = await connectDb()
            students = await db.collection('students').find().toArray() //*Devuelve todos los cursos
        } catch (error) {
            console.console.error(error);
        }
        return students
    },
    getStudent: async (root, { id }) => {
        let db
        let student
        try {
            db = await connectDb()
            student = await db.collection('students').findOne({ _id: ObjectId(id) })
        } catch (error) {
            console.console.error(error);
        }
        return Student
    }
}

Modificamos mutations.js:

const connectDb = require('./db')
const { ObjectId } = require('mongodb')

module.exports = {
    createCourse: async (root, { input }) => {
        const defaults = {
            teacher: '',
            topic: '',
        }
        const newCourse = Object.assign(defaults, input)
        let db
        let course
        try {
            db = await connectDb()
            course = await db.collection('courses').insertOne(newCourse)
            newCourse._id = course.insertedId
        } catch (error) {
            console.error(error)
        }
        return newCourse
    },
    createStudent: async (root, { input }) => {
        let db
        let student
        try {
            db = await connectDb()
            student = await db.collection('students').insertOne(input)
            input._id = student.insertedId
        } catch (error) {
            console.error(error)
        }
        return input
    },
    editCourse: async (root, { _id, input }) => {
        let db
        let course
        try {
            db = await connectDb()
            await db.collection('courses').updateOne({ _id: ObjectId(_id) }, { $set: input })
            course = await db.collection('courses').findOne({ _id: ObjectId(_id) })
        } catch (error) {
            console.error(error)
        }
        return course
    },
    editStudent: async (root, { _id, input }) => {
        let db
        let student
        try {
            db = await connectDb()
            await db.collection('students').updateOne({ _id: ObjectId(_id) }, { $set: input })
            student = await db.collection('students').findOne({ _id: ObjectId(_id) })
        } catch (error) {
            console.error(error)
        }
        return student
    },
    deleteCourse: async (root, { _id }) => {
        let db
        let course
        try {
            db = await connectDb()
            course = await db.collection('courses').findOne({ _id: ObjectId(_id) })
            await db.collection('courses').deleteOne({ _id: ObjectId(_id) })
        } catch (error) {
            console.error(error)
        }
        return `Curso ${_id} eliminado correctamente`
    },
    deleteStudent: async (root, { _id }) => {
        let db
        let student
        try {
            db = await connectDb()
            student = await db.collection('students').findOne({ _id: ObjectId(_id) })
            await db.collection('students').deleteOne({ _id: ObjectId(_id) })
        } catch (error) {
            console.error(error)
        }
        return `Estudiante ${_id} eliminado correctamente`
    }
}

El desafío quedo de esta forma, utilice un nuevo tipo de respuesta y aqui dejo mi código

type Response {
    success: Boolean!
    message: String
}
type Mutation {
"Elimina un curso"
    deleteCourse(_id: ID!): Response
    "Elimina un estudiante"
    deleteStudent(_id: ID!): Response
}
deleteCourse: async (root, {_id})=>{
    let db, response
    try {
      db = await connectDB()
      await db.collection('courses').deleteOne({_id: ObjectId(_id)}).then(()=>{
        response ={
          success: true,
          message: 'Deleted course success'
        }
      }).catch(()=>{
        response ={
          success: false,
          message: 'Invalid Data'
        }
      })
    }catch (err){
      console.error(err)
    }
    return response
  },
  deleteStudent: async (root,{_id}) => {
    let db, response
    try {
      db = await connectDB()
      await db.collection('students').deleteOne({_id: ObjectId(_id)}).then(()=>{
        response ={
          success: true,
          message: 'Deleted student success'
        }
      }).catch(()=>{
        response ={
          success: false,
          message: 'Invalid Data'
        }
      })
    }catch (err){
      console.error(err)
    }
    return response
  }

Por fin avance, despues de un monton de errores pequenos

Lo logre !!
Logre el reto 😃
Schema

<"Eliminar un Curso"
         deleteCourse (id:ID!):Course
   "Eliminar un Estudiante"
         deleteStudent (id: ID!):Student >

Mutation

deleteStudent: async(root, { id })=>{
        let db
        let student
        try{
            db = await conectDB()
            student = await db.collection('student').findOne({_id:ObjectID(id)})
            await db.collection('student').deleteOne({_id:ObjectID(id)})
            console.log("id es"+student)
        }catch(error) {
            console.error("Existe un error al insertar ", error)
        }
        return student
    },deleteCourse: async (root , { id })=>{
        let db
        let course
        try{
            db = await conectDB()
            course = await db.collection('course').findOne({_id:ObjectID(id)})
            await db.collection('course').deleteOne({_id:ObjectID(id)})
            
        }catch(error) {
            console.error("Existe un error al insertar ", error)
        }
        return course


    }

Poco a poco aprendo más, disculpen si me emociono demás.

Si alguien se pregunta como hace el profesor para seleccionar varias palabras seguidas, ctrl + d

Para que la interfás schema.graphql se pinte se puede instarlar esta extensión de Visual Studio Code: ext install kumar-harsh.graphql-for-vscode

Una solución MVP
Schema.grapql

  • query
  • mutation

  "Borra un estudiante"
  deleteStudent(_id: ID!): Boolean

mutations.js


  deleteStudent: async (root, {_id}) =>{
    let db
    let student
    try{
      db = await connectDb()
      await db.collection('students').deleteOne(
         { _id: ObjectID(_id)} 
        )
        student = await db.collection('students').findOne(
        {_id: ObjectID(_id)}
      )
    } catch(err) {
      console.log(err);
    }
    return student?false: true
  }

Mi solución a reto:
schema.graphql

type Mutation {
"Crea un curso"
createCourse(input: CourseInput!): Course
"Edita un curso"
editCourse(_id: ID!, input: CourseEditInput): Course
"Elimina un curso"
deleteCourse(_id: ID!): Course
"Crea un estudiante"
createStudent(input: StudentInput!): Student
"Edita un estudiante"
editStudent(_id: ID!, input: StudentEditInput): Student
"Elimina un estudiante"
deleteStudent(_id: ID!): String
}

mutation.js

deleteStudent: async (root, { _id }) => {
let db, info
try {
db = await connetDb()
info = await db.collection(‘students’).deleteOne({ _id: ObjectID(_id) })
return info.deletedCount ? ‘Se elimino con exito’ : El id ${_id} no existe en la base de datos
} catch (error) {
console.error(error)
}
}

llamado en consola

mutation{
deleteStudent(_id: “…”)
}

Consulta seria recomendable utilizar un api en firebase functions que implemente graphql tanto para el auth como insercion en firestore?

Excelente como funciona todo ❤️!

reto cumplido =) un mutation que permita eliminar tanto un estudiante como un curso.

schema.ghaphql

	"Elimina un elemento"
   	delele(id: ID!, collection: String!): String

mutation.js

delele: async (root, { id, collection }) => {
        let db
        let element

        try {
            db = await connectDb()
            element = await db.collection(collection).deleteOne({ _id: ObjectID(id) })
        } catch (error) {
            console.error(error)
        }
        return element.deletedCount
        ? `El elemento con id ${id} fue eliminado exitosamente de la colecion ${collection}.`
        : `No existe el elemento con el id: ${id} en la colecion ${collection}.`;
    }
deleteCourse: async (root, { _id }) => {
			let db;

			try {
				db = await connectDb();
				await db.collection('courses').deleteOne({ _id: ObjectID(_id) });
			} catch (error) {
				console.log(error);
			}
		},
		deleteStudent: async (root, { _id }) => {
			let db;

			try {
				db = await connectDb();
				await db.collection('students').deleteOne({ _id: ObjectID(_id) });
			} catch (error) {
				console.log(error);
			}
		}```



# Deletes a course
deleteCourse(_id: ID!): [Course]

# Deletes a student
deleteStudent(_id: ID!): [Student]```

Solución al reto.

Schema

 "Elimina un elemento de una colección"
  deleteElement(_id: ID!, collection: String!): Boolean

Resolver

deleteElement: async (root, { _id, collection }) => {
        let db, element

        try {
            db = await connectDB()
            element = await db.collection(collection).findOneAndDelete(
                { _id: ObjectID(_id) }
            )
        } catch (error) {
            console.error(error)
        }

        return element ? true : false
    }

Reto ( el de curso es igual)

Schema

"Operaciones para almacenar informacion"
type Mutation {
  "Create a course"
  createCourse(input: CourseCreateInput!): Course
  "Edit a course"
  editCourse(id: ID!, input: CourseEditInput!): Course
  "Remove a course"
  removeCourse(id: ID!): Course
  "Create a student"
  createStudent(input: StudentCreateInput!): Student
  "Edit a student"
  editStudent(id: ID!, input: StudentEditInput!): Student
  "Remove a student"
  removeStudent(id: ID!): Student
}

Mutation

  removeStudent: async (root, { id }) => {
    let db, student;
    try {
      db = await connectDB();
      student = await db
        .collection('students')
        .findOneAndDelete({ _id: ObjectID(id) });
      console.log(student);
    } catch (error) {
      console.error(error);
    }
    return student.value;
  },

Despues de esta clase puedo decir… los typos nunca son buenos!!!

// schema.graphql
type Mutation {
   ...

    "Remove student"
    removeStudent(_id:ID!): String

    "Remove course"
    removeCourse(_id:ID!): String
}
// mutations.js
...
module.exports = {
    ...
    removeStudent: async (root, { _id }) => {
        let db
        try {
            db = await connectDB()
            await db.collection('students').removeOne(
                { _id: ObjectID(_id) },
            )
        } catch (error) {
            console.error(error);
        }
        return "removed";
    },
    removeCourse: async (root, { _id }) => {
        let db
        try {
            db = await connectDB()
            await db.collection('courses').removeOne(
                { _id: ObjectID(_id) },
            )
        } catch (error) {
            console.error(error);
        }
        return "course removed";
    },
}

Listo 😃

Reto cumplido (TypeScript):

en el schema:

type Mutation {
  "Crea un curso"
  createCourse(input: CourseInputAdd!): Course
  "Edita un curso"
  editCourse(_id: ID!, input: CourseInputEdit!): Course
  "Crea un estudiante"
  createStudent(input: StudentInputAdd!): Student
  "Edita un estudiante"
  editStudent(_id: ID!, input: StudentInputEdit!): Student
  "Elimina un curso"
  deleteCourse(_id: ID!): [Course]
  "Elimina un estudiante"
  deleteStudent(_id: ID!): [Student]
}

por ultimo en el mutation:

  deleteCourse: async (root, { _id }) => {
    let db;
    let courses;
    try {
      db = await connectDB();
      db.collection('courses').deleteOne({ _id: ObjectID(_id) })
      .then(() => console.log('Deleted OK'))
      .catch((err) => console.error('[err]: ', err));
      courses = await db.collection('courses').find().toArray();
    } catch (err) {
      console.error(err);
    }
    return courses;
  },
  deleteStudent: async (root, { _id }) => {
    let db;
    let students;
    try {
      db = await connectDB();
      db.collection('students').deleteOne({ _id: ObjectID(_id) })
      .then(() => console.log('Deleted OK'))
      .catch((err) => console.error('[err]: ', err));
      students = await db.collection('students').find().toArray();
    } catch (err) {
      console.error(err);
    }
    return students;
  },

schema.graphql

type Mutation {
  "Crea un curso"
  createCourse(input: CourseInput!): Course
  "Edita un curso"
  editCourse(_id: ID!, input: CourseEditInput): Course
  "Borrar un curso"
  deleteCourse(_id: ID!): String
  "Crea un estudiante"
  createStudent(input: StudentInput!): Student
  "Edita un estudiante"
  editStudent(_id: ID!, input: StudentEditInput): Student
  "Borra un estudiante"
  deleteStudent(_id: ID!): String
}

mutations.js

    deleteCourse: async (root, { _id }) => {
        let db
        let course

        try {
            db = await connectDb()
            course = await db.collection('courses').deleteOne({ _id: ObjectId(_id) })
        } catch (error) {
            console.error(error)
        }
        
        return course.deleteCount > 0 
    },
    deleteStudent: async (root, { _id }) => {
        let db
        let student

        try {
            db = await connectDb()
            student = await db.collection('students').deleteOne({ _id: ObjectId(_id) })
        } catch (error) {
            console.error(error)
        }
        
        return student.deleteCount > 0
    }

Mi solucion:

deleteCourse: async (root, {id}) => {
        let db = await connectDb(process.env.MONGO_URI)
        await db.collection('courses').deleteOne({_id: ObjectId(id)})
        return 'course with id: ' + id + 'has been deleted'
    },
    deleteStudent: async (root, {id}) => {
        let db = await connectDb(process.env.MONGO_URI)
        await db.collection('students').deleteOne({_id: ObjectId(id)})
        return 'student with id: ' + id + 'has been deleted'
    },

¿cómo se recomienda manejar los Types cuando se trata de consultas que no necesariamente devuelven datos que correspondan con una clase de la lógica del negocio? por ejemplo, el Query va a realizar algunos cálculos sobre los registros antes de retornarlos al cliente, esos fields calculados por decirlo así, ¿deben formar parte de un Type único, definido para dicho Query?

Yo estoy utilizando mongoose y en el lado del servidor hice algo como esto

'use strict'
require('dotenv').config();

// llamando dependencias
const Express = require('express');
const { connect: Connect } = require('mongoose');
const { graphqlHTTP } = require('express-graphql')
const { makeExecutableSchema } = require('graphql-tools')
const { join } = require('path')
const { readFileSync } = require('fs')

// Variables de entorno
const {
    MDB_USER,
    MDB_PASSWORD,
    MDB_HOST,
    MDB_NAME,
    PORT,
} = process.env;


// constantes
const Server = Express();
const MONGOMDB_HOST = `mongodb+srv://${MDB_USER}:${MDB_PASSWORD}@${MDB_HOST}/${MDB_NAME}?retryWrites=true&w=majority`;
const MONGO_OPTION = { useUnifiedTopology: true, useNewUrlParser: true };

const resolvers = require('./lib/resolvers')
const PATH_BASE = join(__dirname, '/lib/')
const typeDefs = readFileSync(`${PATH_BASE}schema.gql`, 'UTF-8')

Server.use('/api', graphqlHTTP({
    schema: makeExecutableSchema({ typeDefs,  resolvers }),
    rootValue: resolvers,
    graphiql: true,
}));

/**
 * Preparando la conexion a Mongo
 */
Connect(MONGOMDB_HOST, MONGO_OPTION, (mongoError) => {
    if (mongoError) {
        console.error('Problemas de conexión a MongoDB Atlas');
        console.log(mongoError);
        process.exit(1);
    }
    /**
     * Inicializando el servidor
    */
    Server.listen(PORT, (error) => {
        console.log('Iniciando el servidor');
        console.log('📡 Conexion establecida con MongoDB Atlas ');
        if (error) {
            console.error('Problemas para inicializar el servidor');
            process.exit(1);
        }
        console.log(`🚀 Servidor Listao en el puerto ${PORT}`)
    })
})

Como pueden ver la conexión se genera al iniciar** Express** y al estar envuelto la conexión se puede hereda, por lo que puede hacer un controlador general para poder realizar un crud base

class DriverDataBase {
    static instanceClass = null;

    /**
     * Permite crear un nuevo registro
     *
     * @param  {Mongoose.Model} Modelo referente a la collecion de mongo
     * @param  {object}    data Datos que seran almacenados
     * @return {object}
     */
    create(model, data) {
        const REGISTER = new model(data);
        REGISTER.save((error, data) => {
            if (error) {
                console.error("Problemas creando el nuevo registro");
                process.exit(1);
            }
        });
        return REGISTER;
    }

     /**
     * Permite buscar registros
     *
     * @param  {Mongoose.Model} Modelo referente a la collecion de mongo
     * @param  {object} query Condiciones de la busqueda
     * @return {object}
     */
    async read(model, query = {}) {
        const DATA = model.find(
            query,
            (error, data) => {
                if (error) {
                    console.error("Problemas al realizar la consulta");
                    console.log(error);
                    process.exit(1);
                }
                return data;
            }
        );
        return DATA;
    }

    /**
     * Permite realiozar la busuqeda por ID
     *
     * @param  {Mongoose.Model} Modelo referente a la collecion de mongo
     * @param  {String}  id Id del registro a buscar
     * @return {object}
     */
    async readId(model, id = 0) {
        const DATA = model.findById(
            id,
            (error, data) => {
                if (error) {
                    console.error("Problemas al realizar la consulta");
                    console.log(error);
                    process.exit(1);
                }
                return data;
            }
        );
        return DATA;
    }

    /**
     * Permite crear un nuevo registro
     *
     * @param  {Mongoose.Model} Modelo referente a la collecion de mongo
     * @para   {string} id Id del registro a buscar
     * @param  {object} updateDate Listado de valores a modificar
     * @return {object}
     */
    async update(model, id, updateData) {
         let response = null;
        await model.updateOne(
            { _id: id}, updateData, { upsert: true },
            (error, { n = 0, nModified = 0 }) => {
                if(error) {
                    console.log("Problemas borrando el registro");
                    process.exit(1);
                }
                response = {
                    success: (n > 0 && nModified > 0),
                    message: (n > 0 && nModified > 0) ? "Registro modificado" : "No se actualizo ningun registro"
                }
            }
        );
        return response;
    }

    /**
     * Permite crear un nuevo registro
     *
     * @param  {Mongoose.Model} Modelo referente a la collecion de mongo
     * @param  {string}  id Identificador del registro a borrar
     * @return {object}
     */
    async delete(model, id =0) {
        const { deletedCount = 0 } = await model.deleteOne(
            { _id: id },
            (error, data) => {
                if (error) {
                    console.log("Problemas borrando el registro");
                    process.exit(1);
                }
                return data;
            }
        )
        return {
            success: deletedCount > 0,
            message: deletedCount ? "Registro borrado" : "No se borro ningun registro"
        };
    }

    /**
     * Consigue una solo instanca de la clase.
     *
     * @return {DriverDataBase}.
     */
    static get instance() {
        if (!DriverDataBase.instanceClass) {
            DriverDataBase.instanceClass = new DriverDataBase();
        }
        return DriverDataBase.instanceClass;
    }
}

module.exports = DriverDataBase;

Y con esa clase la puedo reutilizar para todos los nuevos schemas que se generen ya que dicha clase sería el driver general para el crud. por ejemplo, los queries para curso queda de esta mamera.

'use strict'

const Model = require('./models/Courses');
const Driver = require('./DriverDataBase');
const Instance = Driver.instance;

const Queries = {
    getCourses: async () => await Instance.read(Model),
    getCourse: async (root, args) => {
        const { id = 0 } = args;
        return await Instance.readId(Model, id);
    }
};

module.exports = Queries;

schema.graphql

type Mutation {
	"Crea un curso"
	createCourse(input: CourseInput!): Course
	"Edita un curso"
	editCourse(_id: ID!, input: CourseEditInput!): Course
	"Elimina un curso"
	deleteCourse(_id: ID!): String
	"Crea un estudiante"
	createStudent(input: StudentInput!): Student
	"Edita un estudiante"
	editStudent(_id: ID!, input: StudentEditInput!): Student
	"Elimina un estudiante"
	deleteStudent(_id: ID!): String
}

mutations.js

createCourse: async (root ,{input}) => {
		const defaults = {
			teacher: '',
			topic: ''
		}

		const newCourse = Object.assign(defaults, input)

		let db 
		let course
		try {
			db = await connectDb()
			course = await db.collection('courses').insertOne(newCourse)
			newCourse._id = course.insertedId
		} catch (error) {
			console.error(error)
		}
		return newCourse
	},
	editCourse: async (root ,{_id, input}) => {
		let db 
		let course
		try {
			db = await connectDb()
			await db.collection('courses').updateOne({_id: ObjectID(_id)}, {$set: input})
			course = db.collection('courses').findOne({_id: ObjectID(_id)})
		} catch (error) {
			console.error(error)
		}
		return course
	},
	deleteCourse: async (root ,{_id}) => {
		let db 
		let course
		try {
			db = await connectDb()
			course = await db.collection('courses').deleteOne({_id: ObjectID(_id)})
		} catch (error) {
			console.error(error)
		}
		return `Borrados: ${course.deletedCount}`
	},
	createStudent: async (root ,{input}) => {		
		let db 
		let student
		try {
			db = await connectDb()
			student = await db.collection('students').insertOne(input)
			input._id = student.insertedId
		} catch (error) {
			console.error(error)
		}
		return input
	},
	editStudent: async (root ,{_id, input}) => {
		let db 
		let student
		try {
			db = await connectDb()
			await db.collection('students').updateOne({_id: ObjectID(_id)}, {$set: input})
			student = db.collection('students').findOne({_id: ObjectID(_id)})
		} catch (error) {
			console.error(error)
		}
		return student
	},
	deleteStudent: async (root ,{_id}) => {
		let db 
		let student
		try {
			db = await connectDb()
			student = await db.collection('students').deleteOne({_id: ObjectID(_id)})
		} catch (error) {
			console.error(error)
		}
		return `Borrados: ${student.deletedCount}`
	},