在前面都是直接在schema.js种定义了一些固定值作为数据源。在真实的项目中,肯定要有一个数据存储层的,下面来说说如何使用MongoDB作为数据存储层。
GraphQL系列教程:
- GraphQL的设计理念及安装配置
- Schema的基本使用
- GraphQL中的类型及类型间的关系
- 使用MongoDB作为数据存储层
- 在React中使用GraphQL
- 在AWS Appsync中使用GraphQL
- 如何在serverless中定义GraphQL API-不使用AppSync
- 如何在serverless中定义GraphQL API-使用AppSync并使用Lambda作为数据源
注册MongoDB账号
在这个教程中,使用MongoDB的免费账号就足够了:

创建账号成功后,创建一个共享集群(Shared Cluster):

分别创建Database和Collection:

保存下MongoDB的访问地址:mongodb+srv://lcoding:[email protected]/lcoding
使用Mongoose
首先安装包:
npm install mongoose
然后就可以连接到MongoDB了。连接字符串可以在这里获取:

连接MongoDB的代码:
const mongoose = require('mongoose');
mongoose.connect('mongodb+srv://lcoding.hm1sq.mongodb.net/lcoding', {
auth: {
username: "lcoding",
password: "PASSWORD"
}, useNewUrlParser:true}).then(
() => {
console.log("Database connected");
},
err => {
console.log("Error in database connection. ", err);
}
);
MongoDB model
接下来就可以创建MongoDB的model了,这些model其实就是建立了和MongoDB数据存储层的连接,之后对这些model的操作会自动被保存/更新到MongoDB中。需要注意这些model和GraphQL中的schema不同,那些schema是为了提供访问GraphQL的类型/关系/入口的。
models/Student.js:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const studentSchema = new Schema({
name: String,
address: String,
tutorId: String
});
module.exports = mongoose.model('Student', studentSchema);
models/Tutor.js:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const tutorSchema = new Schema({
name: String
});
module.exports = mongoose.model('Tutor', tutorSchema);
Mutation
所谓mutation,就是对数据的增,删,改等操作。
第一步就是在schema/schema.js中定义对应的操作:
addTutor: {
type: TutorType,
args: {
name: {type: new GraphQLNonNull(GraphQLString)}
},
resolve(parent, args) {
let tutor = new Tutor({
name: args.name
});
return tutor.save();
}
},
需要注意的是,通过GraphQLNonNull可以限制用户输入,保证没有空值。
同时,在暴露GraphQLSchema的时候,不仅要声明query,还要声明mutation:
module.exports = new GraphQLSchema({
query: RootQuery,
mutation: Mutation
});
这样就可以进行这样的插入操作了:
mutation {
addTutor(name: "Dr Tang") {
name
id
}
}
其返回值类似于:
``` json
{
"data": {
"addTutor": {
"name": "Dr Tang",
"id": "616e95e47a7fbbbe6d5b0afb"
}
}
}
如果到MongoDB中查看,也能看到对应的记录:

对于addStudent,则需要通过tutorId连接到Tutor:
addStudent: {
type: StudentType,
args: {
name: {type: new GraphQLNonNull(GraphQLString)},
address: {type: new GraphQLNonNull(GraphQLString)},
tutorId: {type: new GraphQLNonNull(GraphQLID)}
},
resolve(parent, args) {
let student = new Student({
name: args.name,
address: args.address,
tutorId: args.tutorId
});
return student.save();
}
}
在发出请求的时候是这样的,需要注意tutorId目前只能通过MongoDB web UI来获取:
mutation {
addStudent(name:"Chole",address:"11 Fake Street",tutorId:"616e95e47a7fbbbe6d5b0afb") {
name
address
}
}
更新resolve方法
首先来看看StudentType的定义, 需要注意的是,在resolve方法中,使用的是parent.tutorId,而不是args.id,同时调用的是Tutor.findById,而不是Student.findById:
const StudentType = new GraphQLObjectType({
name: 'Student',
fields: () => ({
id: {type: GraphQLID},
name: {type: GraphQLString},
address: {type: GraphQLString},
tutor: {
type: TutorType,
resolve(parent, args) {
return Tutor.findById(parent.tutorId)
}
}
})
});
这样就可以查询学生及相关tutor的信息了:
{
students {
name
address
tutor {
name
}
}
}
这个查询可以返回所有相关的学生信息:
{
"data": {
"students": [
{
"name": "Lucas",
"address": "1 Fake Street",
"tutor": {
"name": "Lucas"
}
},
{
"name": "Paul",
"address": "2 Fake Street",
"tutor": {
"name": "Paul"
}
},
{
"name": "Emily",
"address": "3 Fake Street",
"tutor": {
"name": "Emily"
}
},
{
"name": "Lucy",
"address": "4 Fake Street",
"tutor": {
"name": "Lucy"
}
},
{
"name": "Jess",
"address": "5 Fake Street",
"tutor": {
"name": "Jess"
}
},
{
"name": "Jess",
"address": "5 Fake Street",
"tutor": {
"name": "Jess"
}
},
{
"name": "Steve",
"address": "6 Fake Street",
"tutor": {
"name": "Steve"
}
},
{
"name": "Luke",
"address": "7 Fake Street",
"tutor": {
"name": "Luke"
}
},
{
"name": "Dan",
"address": "8 Fake Street",
"tutor": {
"name": "Dan"
}
},
{
"name": "Ned",
"address": "9 Fake Street",
"tutor": {
"name": "Ned"
}
},
{
"name": "Tom",
"address": "10 Fake Street",
"tutor": {
"name": "Tom"
}
},
{
"name": "Chole",
"address": "11 Fake Street",
"tutor": {
"name": "Chole"
}
}
]
}
}
与此类似,TutorType中的resolve方法:
resolve(parent, args) {
return Student.find({tutorId: parent.id})
}
在RootQuery中student及students两个入口:
student: {
type: StudentType,
args: {id: {type: GraphQLID}},
resolve(parent, args) {
return Student.findById(args.id)
}
},
students: {
type: new GraphQLList(StudentType),
resolve(parent, args) {
return Student.find({});
}
}
tutor和tutors两个入口的定义类似。