1

I'm learning graphql and working on a simple API with mongodb database. I can't figure out why the relationship declared in my schema is not working :

type People {
    id:ID!
    firstName:String!
    lastName:String!
    email:String!
    serviceId:String
    apps:[String]
    service:Service
}
type Service {
    id:ID!
    name:String!
    location:String!
    peoples:[People]
}

When I run this query:

query getLocationByPerson {
   People {
      firstName
      lastName
      service {
        location
      }
   }
}

Here's what I get:

"People": [
      {
        "firstName": "John",
        "lastName": "DOE",
        "service": null
      },
      {
        "firstName": "Jane",
        "lastName": "DOE",
        "service": null
      }
]

Any idea of what I'm missing here?

2

1 Answer 1

0

The issue lays in your resolvers:

Based on the repo you linked your queries look like the following:

const People = require('../database/people');
const Service = require('../database/service');
const queries = {
    People: () => People.find({}),
    ...
    Service: () => Service.find({}),
    ...
  };

module.exports = queries;

The People schema looks like this:

const mongoose = require('mongoose');

const Schema = mongoose.Schema;
const peopleSchema = new Schema({
    Xid: { type: String },
    firstName: { type: String },
    lastName: { type: String },
    email: { type: String },
    apps: { type: Array },
    serviceId: { type: String },
    service: { type: Schema.Types.ObjectId, ref: 'service' }
},{ versionKey: false })

module.exports = mongoose.model('people', peopleSchema);

People.find() will return only the service _id though not the whole service object. That is why you get null in the response.

The GraphQL relationship you implemented in People has a Service Type while you're getting back from the db only the service _id.

You have 2 solutions:

A) You want to retrieve the Service object as well when you query for People. In this case you need to use the mongoose populate function: People: () => People.find({}).populate('service'),

The above will provide People with the referenced Service object (not just the _id)

Because you're using id instead of _id in your schema the above is not enough and you need to use the following instead where you also create an id field to return for each service

People: async () => {
      const people = await People.find({}).populate('service').exec()
      return people.map(person => ({
        ...person._doc,
        id: person._doc._id,
        service: {
          ...person._doc.service._doc,
          id: person._doc.service._doc._id,
        },
      }))
    }, return people
}

The above is quite convulted. I'd strongly suggest going with solution (B)

Docs about populate(): https://mongoosejs.com/docs/populate.html

B) User a type resolver

// Type.js
const Service = require('../database/service');
const types = {
    People: {
      // you're basically saying: In People get service field and return...
      service: ({ service }) => Service.findById(service), // service in the deconstructed params is just an id coming from the db. This param comes from the `parent` that is People
    },
   Service: {
     id: ({_id}) => _id, // because you're using id in your schema
},
  };

module.exports = queries;

A note on the implementation of this option:

Sign up to request clarification or add additional context in comments.

10 Comments

thanks for your help. I tried the A) solution but im still getting null result for the location field. And the following error: `` Error: Cannot return null for non-nullable field Service.location. ``
That is probably because you have id: ID! in your type Service while _id is, I guess, coming back from the db. As I guess you do not want to use the type resolver option for the field id as well I'm editing my answer to fix that error
Thanks again. I'm new to node.js, graphql & mongodb so I'm probably not implementing your solutions properly because I still get the null result. Would you mind to create a pull request in my repo please?
Please add first the package.json to your repo.
Looking more deeply in your code I am afraid you might not store data as it should be in the first place. Can you add to your repo an actual sample object coming from your db for both one People and the related Service?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.