Tyl*_*tec 6 many-to-many graphql
假设我有两个对象数组:
let movies = [
{ id: '1', title: 'Erin Brockovich'},
{ id: '2', title: 'A Good Year'},
{ id: '3', title: 'A Beautiful Mind'},
{ id: '4', title: 'Gladiator'}
];
let actors = [
{ id: 'a', name: 'Julia Roberts'},
{ id: 'b', name: 'Albert Finney'},
{ id: 'c', name: 'Russell Crowe'}
];
Run Code Online (Sandbox Code Playgroud)
我想在他们之间建立多对多关系。首先使用Vanilla JavaScript,最后使用GraphQL模式。
In JavaScript I did something like this:
let movies = [
{ id: '1', title: 'Erin Brockovich', actorId: ['a', 'b'] },
{ id: '2', title: 'A Good Year', actorId: ['b', 'c'] },
{ id: '3', title: 'A Beautiful Mind', actorId: ['c'] },
{ id: '4', title: 'Gladiator', actorId: ['c'] }
];
let actors = [
{ id: 'a', name: 'Julia Roberts', movieId: ['1'] },
{ id: 'b', name: 'Albert Finney', movieId: ['1', '2'] },
{ id: 'c', name: 'Russell Crowe', movieId: ['2', '3', '4'] }
];
let actorIds = [];
let movieIds = [];
for (let m = 0; m < movies.length; m ++) {
for (let i = 0; i < movies[m].actorId.length; i ++) {
actorIds.push(movies[m].actorId[i]);
}
}
for (let a = 0; a < actors.length; a ++) {
for (let i = 0; i < actors[a].movieId.length; i ++) {
movieIds.push(actors[a].movieId[i]);
}
}
for (let a = 0; a < actors.length; a ++) {
for (let i = 0; i < actorIds.length; i ++) {
if ((actors[a].id == 'c') && (actors[a].id == actorIds[i])) {
for (let j = 0; j < movies.length; j ++) {
if (movies[j].id == movieIds[i]) {
console.log(movies[j].title);
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
When I run preceding code in Node, Terminal will return
A Good Year
A Beautiful Mind
Gladiator
Run Code Online (Sandbox Code Playgroud)
and this is exactly what I want.
Unfortunately I've get lost in GraphQL schema. What I have so far—inside of fields function of course—is this:
in_which_movies: {
type: new GraphQLList(FilmType),
resolve(parent, args) {
let actorIds = [];
let movieIds = [];
for (let m = 0; m < movies.length; m ++) {
for (let i = 0; i < movies[m].actorId.length; i ++) {
actorIds.push(movies[m].actorId[i]);
}
}
for (let a = 0; a < actors.length; a ++) {
for (let i = 0; i < actors[a].movieId.length; i ++) {
movieIds.push(actors[a].movieId[i]);
}
}
for (var a = 0; a < actors.length; a ++) {
for (var i = 0; i < actorIds.length; i ++) {
if ((actors[a].id == parent.id) && (actors[a].id == actorIds[i])) {
for (var j = 0; j < movies.length; j ++) {
if (movies[j].id == movieIds[i]) {
console.log(movies[j].title);
}
}
}
}
}
return movies[j].title;
}
}
Run Code Online (Sandbox Code Playgroud)
When I run the following query in GraphiQL...
{
actor(id: "c") {
name
in_which_movies {
title
}
}
}
Run Code Online (Sandbox Code Playgroud)
...I have this response:
{
"errors": [
{
"message": "Cannot read property 'title' of undefined",
"locations": [
{
"line": 4,
"column": 3
}
],
"path": [
"actor",
"in_which_movies"
]
}
],
"data": {
"actor": {
"name": "Russell Crowe",
"in_which_movies": null
}
}
}
Run Code Online (Sandbox Code Playgroud)
...which is strange for me, cuz Terminal is responding as I expected
A Good Year
A Beautiful Mind
Gladiator
Run Code Online (Sandbox Code Playgroud)
I guess all code I've wrote so far is useless and I need some fresh guidelines how to write many-to-many relationship in GraphQL properly.
TL; DR我认为您太想太多了。您的解析器做的工作太多了,导致代码难以推理和调试。
我认为您的问题与GraphQL并没有太大关系,而只是对基础数据进行正确的操作。我将尝试从您的示例以及GraphQL逐步解决它,因此我们最终提供了您正在寻找的类型和解析器。
从您的原始代码开始:
let movies = [
{ id: '1', title: 'Erin Brockovich', actorId: ['a', 'b'] },
{ id: '2', title: 'A Good Year', actorId: ['b', 'c'] },
{ id: '3', title: 'A Beautiful Mind', actorId: ['c'] },
{ id: '4', title: 'Gladiator', actorId: ['c'] }
];
let actors = [
{ id: 'a', name: 'Julia Roberts', movieId: ['1'] },
{ id: 'b', name: 'Albert Finney', movieId: ['1', '2'] },
{ id: 'c', name: 'Russell Crowe', movieId: ['2', '3', '4'] }
];
Run Code Online (Sandbox Code Playgroud)
我想建议我们将其翻译为索引为的内容,id以便于查询。这也将更好地为通常在生产GraphQL API之后的数据库或键值存储建模。
将其转换为已索引但仍为原始JS的内容:
let movies = {
'1': { id: '1', title: 'Erin Brockovich', actorId: ['a', 'b'] },
'2': { id: '2', title: 'A Good Year', actorId: ['b', 'c'] },
'3': { id: '3', title: 'A Beautiful Mind', actorId: ['c'] },
'4': { id: '4', title: 'Gladiator', actorId: ['c'] }
};
let actors = {
'a': { id: 'a', name: 'Julia Roberts', movieId: ['1'] },
'b': { id: 'b', name: 'Albert Finney', movieId: ['1', '2'] },
'c': { id: 'c', name: 'Russell Crowe', movieId: ['2', '3', '4'] }
};
Run Code Online (Sandbox Code Playgroud)
接下来,我们应该考虑将代表这些类型的GraphQL模式。这是“多对多”部分起作用的地方。我认为我们可以从您的示例数据中清晰地得出类型:
type Movie {
id: ID!
title: String
actors: [Actor]
}
type Actor {
id: ID!
name: String
movies: [Movie]
}
Run Code Online (Sandbox Code Playgroud)
请注意,这[Movie]是一个Movie对象列表。即使基础数据包含ID(也就是我们希望的那样,也称为“规范化”),我们也会根据实际的类型关系对API进行建模。
接下来,我们需要设置解析器。让我们看一下Actor类型的解析器,因为这就是您的示例。
movies: {
type: new GraphQLList(FilmType),
resolve(parent) {
// The ids of all the movies this actor is in. "parent" will be the
// actor data currently being queried
let movieIds = parent.movieId;
// We'll build up a list of the actual movie datas to return.
let actorInMovies = [];
for (let m = 0; m < movieIds.length; m++) {
// The m'th movie id.
let movieId = movieIds[m];
// The movie data from our indexed "movies" top level object.
// In production, this might access a database service
let movie = movies[movieID];
// Add that movie to the list of movies
actorInMovies.push(movie)
}
// Then we'll return that list of movie objects.
return actorInMovies;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,在您的原始解析程序中,您返回movies[j].title的可能是字符串,并且与“ List of FilmType”所期望的不匹配,并且在上面的示例中,我返回了电影数据对象的数组。
另外,上面的代码是执行此操作的非常冗长的方法,但是我认为对每个步骤进行注释将很有帮助。要真正实现多对多,则该Movie类型的actors字段应具有几乎相同的代码。但是,只是为了显示一个示例,说明如何通过使用.map()运算符来大大简化此代码,我将用另一种方式编写它:
actors: {
type: new GraphQLList(ActorType),
resolve(parent) {
// In this case, "parent" will be the movie data currently being queried.
// Use "map" to convert a list of actor ids into a list of actor data
// objects using the indexed "actors" top level object.
return parent.actorId.map(id => actors[id]);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3220 次 |
| 最近记录: |