graphql-compose-elasticsearch
graphql-compose-elasticsearch copied to clipboard
hits returns me the found id, score, type... but not the other fields
Hi
I am just starting with ElasticSearch and maybe it is something obvious but I can't figure it out why I can't get all the info with my query.
I used the TypeComposer example to create my own and then I query with:
{
searchActivities(
query: {
multi_match: {
query: "blur",
fields: ["title", "description"]
}
}
){
hits
}
}
But I get only:
"searchActivities": {
"hits": [
{
"_index": "myfirstindex",
"_type": "activities",
"_id": "2",
"_score": 0.2876821
}
]
}
With the other demo "API Proxy" I could get the other info, but I saw that every ES method was available, including creation or deletion of indices and I want this /graphql endpoint to be public.
Can someone point me in the right direction?
Thanks
GraphQL designed for mobile devices and returns only that fields which were requested.
So you need add more fields to your query:
{
searchActivities(q: "blur"){ # simplify query for demo purposes
hits {
_id
_score
_source # <--- request data for `hit`, maybe you will need to provide subfields names
}
}
}
I tried that, but hits its a JSON field and has not subfields.
That's what GraphQL says:
Field \"hits\" must not have a selection since type \"JSON\" has no subfields
Please provide code how you create a schema or demo-repo without connection string. I try to resolve it tomorrow. Maybe some bug or improper using of a TypeComposer in the code which should be documented.
Sure.
This is my schema:
const mapping = {
properties: {
id: {
type: 'keyword',
},
title: {
type: 'text',
},
description: {
type: 'text',
},
},
};
const activitiesES = composeWithElastic({
graphqlTypeName: 'searchActivities',
elasticIndex: 'myindex',
elasticType: 'activities',
elasticMapping: mapping,
elasticClient: new Elasticsearch.Client({
host: ELASTICSEARCH_HOST,
apiVersion: ELASTICSEARCH_API_VERSION,
log: 'info',
}),
});
elasticField = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
searchActivities: activitiesES.getResolver('search').getFieldConfig(),
},
}),
});
These are the software version's I am using:
"elasticsearch": "^14.0.0",
"graphql": "^0.10.5",
"graphql-compose": "^2.10.1",
"graphql-compose-elasticsearch": "^1.8.5",
"graphql-tools": "2.7.2",
Let me know if that's enough
Look at added test cases.
It works correctly - composeWithElastic
provide proper types. And _source
field has SearchActivitiesSearchActivities
type instead of JSON
.
Needs more details from your code. For building a proper test case.
I found something... weird :S
When I first start my graphql server locally, the first query would work like you expected, but the second one will change hits return type to JSON :S
In my local, your test also pass ok by the way.
Here's the code I have: graphql.zip
Something else...
So, the first time it works, second, hits is a JSON array, and third is just a JSON. Don't know where I messed up :S
WoW 😱 First time I see such problem.
It looks like you generate the schema for every request. It's wrong! You should generate schema only once at node startup. And then use schema instance for every request. And your queries will work much faster!
Anyway for me is very interesting what error you catch on here https://github.com/graphql-compose/graphql-compose-elasticsearch/blob/ffb6f9494085c80a1c67c89ece182a45c9095dcb/src/resolvers/search.js#L94-L96
Just add throw e;
in your installed package node_modules/graphql-compose-elasticsearch/lib/resolvers/search.js
(due babel transpilling line numbers will be other).
The error it throws there is:
Error: Cannot get field 'hits' from type 'searchActivitiesSearchHitItem'. Field does not exist.
About generating the schema for every request, do you think is wrong in my case? because this code is intended to be an Amazon Lambda function, so in my mind is not like express that would be running indefinetly, but it will just run when the Lambda function would be invoked. Am I wrong?
Found out something else.
I moved the composeSchemas function outside the handler, but in my local it makes the same result. But, I deployed it on Amazon Lambda and everything works as expected there, I don't have the hits changing its return type.
So, something about running the code on local is the problem, something about how serverless-offline plugin works maybe or some conflict.
Thanks for provided error. Now all became clear to me. With your setup schema is really creates for every request call. So creating schema outside handler is a right solution.
Problem with serverless code running on your local machine:
It really looks like a bug, that code outside handler runs for every request. Bug maybe in their code or maybe you missed something in the setup.
Problem with graphql-compose-elasticsearch:
https://github.com/graphql-compose/graphql-compose-elasticsearch/blob/ffb6f9494085c80a1c67c89ece182a45c9095dcb/src/resolvers/search.js#L90-L102
This code can work only once after that type for hit
field changes, and if this code runs again, then hit
fields contains modified type. Thas why first query execution works correctly, second return [JSON]
and third and further runs returns JSON
type for hit
field.
Really I don't know should I somehow fix my code for working with such use case. I think better will be to throw an exception if I somehow detect that createSearchResolver
calls in the second time. Cause construction of resolver or types should be done only once.