Apollo/GraphQL:如何获取嵌套元素?
Posted
技术标签:
【中文标题】Apollo/GraphQL:如何获取嵌套元素?【英文标题】:Apollo/GraphQL: How to get nested elements? 【发布时间】:2018-04-06 17:04:55 【问题描述】:这是我的 mongoDB 的示例文档。我需要通过 Apollo/GraphQL 获取 content.en
数组。但是嵌套对象对我来说是个问题。
en
是语言标签,如果可以作为变量使用就好了。
MongoDB 中的数据
"_id" : "9uPjYoYu58WM5Tbtf",
"content" :
"en" : [
"content" : "Third paragraph",
"timestamp" : 1484939404
]
,
"main" : "Dn59y87PGhkJXpaiZ"
graphQL 结果应该是:
"data":
"article": [
"_id": "9uPjYoYu58WM5Tbtf",
"content": [
"content" : "Third paragraph",
"timestamp" : 1484939404
]
]
也就是说,我需要获取 ID 和特定语言的内容数组。
但这不是,我通过以下设置得到的结果:
类型
const ArticleType = new GraphQLObjectType(
name: 'article',
fields:
_id: type: GraphQLID ,
content: type: GraphQLString
)
GraphQL 架构
export default new GraphQLSchema(
query: new GraphQLObjectType(
name: 'RootQueryType',
fields:
article:
type: new GraphQLList(ArticleType),
description: 'Content of article dataset',
args:
id:
name: 'id',
type: new GraphQLNonNull(GraphQLID)
,
async resolve ( db , args)
return db.collection('articles').find( main: args.id ).toArray()
)
)
查询
article(id: "Dn59y87PGhkJXpaiZ")
_id,
content
结果
"data":
"article": [
"_id": "9uPjYoYu58WM5Tbtf",
"content": "[object Object]"
]
【问题讨论】:
您希望查询返回什么?您能否将其添加到您的问题中? @DevNebulae 我已经发布了。请参阅第二个代码块。 "graphQL 结果应该是" 我相信您需要两个参数,id 参数来过滤根解析上的文章和语言参数来过滤子解析上的内容。因此 mongo 查询将返回所有匹配的文章 id 与所有语言内容,graphql 将返回基于语言 arg 的内容。还将内容映射到架构。 【参考方案1】:您可以使用以下代码。
String query =
article(id: "Dn59y87PGhkJXpaiZ")
_id,
content(language:"en")
content,
timestamp
const ContentType = new GraphQLObjectType(
name: 'content',
fields:
content: type: GraphQLString ,
timestamp: type: GraphQLInt
)
const ArticleType = new GraphQLObjectType(
name: 'article',
fields:
_id: type: GraphQLID ,
content:
type: new GraphQLList(ContentType),
args:
language:
name: 'language',
type: new GraphQLNonNull(GraphQLString)
,
async resolve (args)
return filter content here by lang
)
export default new GraphQLSchema(
query: new GraphQLObjectType(
name: 'RootQueryType',
fields:
article:
type: new GraphQLList(ArticleType),
description: 'Content of article dataset',
args:
id:
name: 'id',
type: new GraphQLNonNull(GraphQLID)
,
async resolve ( db , args)
return db.collection('articles').find( main: args.id).toArray()
)
)
Java 示例:
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import graphql.ExecutionResult;
import graphql.GraphQL;
import graphql.schema.*;
import org.bson.Document;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static graphql.Scalars.*;
import static graphql.schema.GraphQLArgument.newArgument;
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
import static graphql.schema.GraphQLObjectType.newObject;
import static graphql.schema.GraphQLSchema.newSchema;
public class GraphQLTest
private static final ArticleRepository articleRepository;
public static class ArticleRepository
private final MongoCollection<Document> articles;
ArticleRepository(MongoCollection<Document> articles)
this.articles = articles;
public List<Map<String, Object>> getAllArticles(String id)
List<Map<String, Object>> allArticles = articles.find(Filters.eq("main", id)).map(doc -> (Map<String, Object>)doc).into(new ArrayList<>());
return allArticles;
public static void main(String... args)
String query = "\n" +
" article(id: \"Dn59y87PGhkJXpaiZ\") \n" +
" _id,\n" +
" content(language:\"en\") \n" +
" content,\n" +
" timestamp\n" +
" \n" +
" \n" +
"";
ExecutionResult result = GraphQL.newGraphQL(buildSchema()).build().execute(query);
System.out.print(result.getData().toString());
static
MongoDatabase mongo = new MongoClient().getDatabase("test");
articleRepository = new ArticleRepository(mongo.getCollection("articles"));
private static GraphQLSchema buildSchema()
GraphQLObjectType ContentType = newObject().name("content")
.field(newFieldDefinition().name("content").type(GraphQLString).build())
.field(newFieldDefinition().name("timestamp").type(GraphQLInt).build()).build();
GraphQLObjectType ArticleType = newObject().name("article")
.field(newFieldDefinition().name("_id").type(GraphQLID).build())
.field(newFieldDefinition().name("content").type(new GraphQLList(ContentType))
.argument(newArgument().name("language").type(GraphQLString).build())
.dataFetcher(dataFetchingEnvironment ->
Document source = dataFetchingEnvironment.getSource();
Document contentMap = (Document) source.get("content");
ArrayList<Document> contents = (ArrayList<Document>) contentMap.get(dataFetchingEnvironment.getArgument("lang"));
return contents;
).build()).build();
GraphQLFieldDefinition.Builder articleDefinition = newFieldDefinition()
.name("article")
.type(new GraphQLList(ArticleType))
.argument(newArgument().name("id").type(new GraphQLNonNull(GraphQLID)).build())
.dataFetcher(dataFetchingEnvironment -> articleRepository.getAllArticles(dataFetchingEnvironment.getArgument("id")));
return newSchema().query(
newObject()
.name("RootQueryType")
.field(articleDefinition)
.build()
).build();
【讨论】:
您对此也有提示吗? ***.com/questions/46929327/… 这个问题似乎与这个问题非常相似。您是否将结构更改为新结构?现在有新的收藏内容吗?我相信这里提供的答案会在一定程度上起作用。有什么区别? 我只对示例代码稍作改动。我真的被困在那个嵌套上。首先,我认为这应该很简单,因为您是对的,这似乎是非常相似的问题...【参考方案2】:既然你说语言 ISO 代码应该是一个参数,并且内容取决于语言 ISO 代码(从现在开始我将其称为 languageTag
),我认为你应该编辑你的架构看起来像这样:
export default new GraphQLSchema(
query: new GraphQLObjectType(
name: 'RootQueryType',
fields:
article:
type: new GraphQLList(ArticleType),
description: 'Content of article dataset',
args:
id:
name: 'id',
type: new GraphQLNonNull(GraphQLID)
,
// Edited this part to add the language tag
languageTag:
name: 'languageTag',
type: new GraphQLNonNull(GraphQLString)
,
async resolve ( db , args)
return db.collection('articles').find( main: args.id ).toArray()
)
)
但是,这仍然不能解决您检索内容的问题。我认为您需要在架构中添加另一种类型,称为 ContentType
。
const ContentType = new GraphQLObjectType(
name: 'ContentType',
fields:
content:
type: GraphQLString,
resolve: (root, args, context) => root.content[args.languageTag].content
,
timestamp:
type: GraphQLString,
resolve: (root, args, context) => root.content[args.languageTag].timestamp
,
)
我想提出的最后一个问题是,您将单个article
作为Array
返回。我建议将其更改为返回单个对象。最后但并非最不重要的一点是,您的架构看起来像这样:
export default new GraphQLSchema(
query: new GraphQLObjectType(
name: 'RootQueryType',
fields:
article:
type: new GraphQLList(ArticleType),
description: 'Content of article dataset',
args:
id:
name: 'id',
type: new GraphQLNonNull(GraphQLID)
,
// Edited this part to add the language tag
languageTag:
name: 'languageTag',
type: new GraphQLNonNull(GraphQLString)
,
// Add the extra fields to the article
fields:
content: ContentType
async resolve ( db , args)
return db.collection('articles').findOne( main: args.id )
)
)
这段代码可能有点偏离,因为我没有你的数据库来测试它。我认为这是朝着正确方向的一个很好的推动。
【讨论】:
语言字段是一个数组,因为有多个内容对象。在我的示例中,只有一个对象。但我需要去阵列。 @user3142695 你能给出你的问题的模式吗?我认为我们错过了一大块拼图。 我想我理解你想要做什么,但我仍然得到了结果"content": "[object Object]"
解析字段是否在ContentType
中触发? IE。你有没有把console.log
放在那里,看看是否可以到达?
我必须将额外的内容字段移动到 ArticleType
并在那里添加语言参数和解析。有了它,它就可以工作了。感谢您的帮助和提示。【参考方案3】:
我认为问题出在这一行:
content: type: GraphQLString
。尝试将内容提取到另一个GraphQLObjectType
,然后将其作为content
字段传递给ArticleType
编辑
试试这个:
const ContentType = new GraphQLObjectType(
name: 'content',
fields:
en: type: GraphQLList ,
it: type: GraphQLList
// ... other languages
)
【讨论】:
对我来说有两个问题?字段en
是可变的。也可能有de
或it
。所以我需要使用一个变量来获取正确的语言对象。我坚持这一点。第二件事是,这是一个数组,所以 GraphQLString
不会在这里工作,对吧?您能否发布一些代码以便更好地理解?以上是关于Apollo/GraphQL:如何获取嵌套元素?的主要内容,如果未能解决你的问题,请参考以下文章