GraphQL关系返回null
我正在学习graphql并使用mongodb数据库处理一个简单的API。我无法弄清楚为什么在我的架构中声明的关系不起作用:
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]
}
当我运行此查询时:
query getLocationByPerson {
People {
firstName
lastName
service {
location
}
}
}
这是我得到的:
"People": [
{
"firstName": "John",
"lastName": "DOE",
"service": null
},
{
"firstName": "Jane",
"lastName": "DOE",
"service": null
}
]
知道我在这里缺少什么吗?
回答如下:问题出在您的解析器中:
根据您链接的回购,您的查询如下所示:
const People = require('../database/people');
const Service = require('../database/service');
const queries = {
People: () => People.find({}),
...
Service: () => Service.find({}),
...
};
module.exports = queries;
People架构如下所示:
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()
将仅返回服务_id
,但不返回整个服务对象。这就是为什么你在响应中得到null
。
您在People中实现的GraphQL关系有一个Service Type
,而您只从服务_id
返回数据库。
你有2个解决方案:
A)您在查询People时也想检索Service对象。在这种情况下,您需要使用mongoose populate
函数:People: () => People.find({}).populate('service'),
以上将为People提供引用的Service对象(而不仅仅是_id)
因为你在模式中使用id
而不是_id
,所以上面是不够的,你需要使用以下代码,你也可以创建一个id
字段来为每个服务返回
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
}
以上是非常令人沮丧的。我强烈建议采用解决方案(B)
关于populate()的文章:https://mongoosejs/docs/populate.html
B)用户使用type
解析器
// 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;
关于此选项实施的说明:
- 它是我的首选,虽然你最终需要一个dataloader来批量调用db,否则它将是非常低效的。基本上,您需要解决N + 1问题并确保有效查询数据库。这里有一篇非常好的文章:http://www.petecorey/blog/2017/08/14/batching-graphql-queries-with-dataloader/?from=east5th.co