node.js - 如何使用“graphql-compose-elasticsearch”重构 GraphQL 模式以将 GraphQL 查询转换为 Elasticsearch 查询?
问题描述
我在localhost:3000
(REST api)上使用 json 服务器托管我的数据并使用 GraphQL 来获取数据,现在我想将数据移动到 Elastic Search 服务器中,我仍然想使用 GraphQL 作为 API 网关。我尝试使用这个graphql-compose-elasticsearch
库来使用 GraphQL 作为 ElasticSearch 的代理。
https://github.com/graphql-compose/graphql-compose-elasticsearch
在我最初的 GraphQL 模式中,我定义了类型、根查询、解析器。代码是这样的:
const graphql = require('graphql');
const axios = require('axios');
const {
GraphQLObjectType,
GraphQLList,
GraphQLID,
GraphQLInt,
GraphQLString,
GraphQLBoolean,
GraphQLSchema,
GraphQLNonNull
} = graphql;
const RoomType = new GraphQLObjectType({
name: 'RoomType',
fields: () => ({
id: { type: GraphQLID },
roomName: { type: GraphQLString },
roomNumber: { type: GraphQLString },
floorId: { type: GraphQLInt },
hasImages: { type: GraphQLBoolean },
hasGLTF: { type: GraphQLBoolean },
hasPhotogrammetry: { type: GraphQLBoolean },
hasPointClouds: { type: GraphQLBoolean },
roomDescription: { type: GraphQLString },
floor: {
type: FloorType,
resolve(parentValue, args) {
return axios
.get(`http://localhost:3000/floors/${parentValue.floorId}`)
.then((resp) => resp.data);
}
},
assets: {
type: new GraphQLList(AssetType),
resolve(parentValue, args) {
return axios
.get(`http://localhost:3000/rooms/${parentValue.id}/assets`)
.then((resp) => resp.data);
}
}
})
});
const FloorType = new GraphQLObjectType({
name: 'FloorType',
fields: () => ({
id: { type: GraphQLID },
floorName: { type: GraphQLString },
floorDescription: { type: GraphQLString },
rooms: {
type: new GraphQLList(RoomType),
resolve(parentValue, args) {
return axios
.get(`http://localhost:3000/floors/${parentValue.id}/rooms`)
.then((resp) => resp.data);
}
}
})
});
const AssetType = new GraphQLObjectType({
name: 'AssetType',
fields: () => ({
id: { type: GraphQLID },
category: { type: GraphQLString },
assetName: { type: GraphQLString },
assetNumber: { type: GraphQLString },
roomId: { type: GraphQLString },
location: { type: GraphQLString },
isHeritageAsset: { type: GraphQLBoolean },
hasImages: { type: GraphQLBoolean },
hasGLTF: { type: GraphQLBoolean },
hasPhotogrammetry: { type: GraphQLBoolean },
hasPointClouds: { type: GraphQLBoolean },
assetDescription: { type: GraphQLString },
room: {
type: RoomType,
resolve(parentValue, args) {
return axios
.get(`http://localhost:3000/rooms/${parentValue.roomId}`)
.then((resp) => resp.data);
}
}
})
});
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
getRoom: {
type: RoomType,
args: { id: { type: new GraphQLNonNull(GraphQLID) } },
resolve(parentValue, { id }) {
return axios.get(`http://localhost:3000/rooms/${id}`).then((resp) => resp.data);
}
},
getFloor: {
type: FloorType,
args: { id: { type: new GraphQLNonNull(GraphQLID) } },
resolve(parentValue, { id }) {
return axios.get(`http://localhost:3000/floors/${id}`).then((resp) => resp.data); //to make it compatible between axios and graphql, a workaround
}
},
getAsset: {
type: AssetType,
args: { id: { type: new GraphQLNonNull(GraphQLID) } },
resolve(parentValue, { id }) {
return axios.get(`http://localhost:3000/assets/${id}`).then((resp) => resp.data); //to make it compatible between axios and graphql, a workaround
}
},
getAllRooms: {
type: new GraphQLList(RoomType),
resolve() {
return axios.get(`http://localhost:3000/rooms`).then((resp) => resp.data);
}
},
getAllAssets: {
type: new GraphQLList(AssetType),
resolve() {
return axios.get(`http://localhost:3000/assets`).then((resp) => resp.data);
}
},
getAllFloors: {
type: new GraphQLList(FloorType),
resolve() {
return axios.get(`http://localhost:3000/floors`).then((resp) => resp.data);
}
}
}
});
//expose this to the rest of the application
module.exports = new GraphQLSchema({
query: RootQuery
});
对于 Elasticsearch,版本是 7.0。我在 上运行localhost:9200
,我有 3 个索引,rooms
、floors
和assets
,每个索引都有一个映射。我试着这样编码:
const graphql = require('graphql');
const graphql_compose_elasticsearch = require('graphql-compose-elasticsearch');
const { elasticApiFieldConfig, composeWithElastic } = graphql_compose_elasticsearch;
const { GraphQLSchema, GraphQLObjectType } = graphql;
const elasticsearch = require('elasticsearch');
// Mapping obtained from ElasticSearch server
const floor_mapping = {
properties: {
floorId: {
type: 'text',
fields: {
keyword: {
type: 'keyword',
ignore_above: 256
}
}
},
hasGLTF: {
type: 'boolean'
},
hasImages: {
type: 'boolean'
},
hasPhotogrammetry: {
type: 'boolean'
},
hasPointClouds: {
type: 'boolean'
},
roomDescription: {
type: 'text',
fields: {
keyword: {
type: 'keyword',
ignore_above: 256
}
}
},
roomName: {
type: 'text',
fields: {
keyword: {
type: 'keyword',
ignore_above: 256
}
}
},
roomNumber: {
type: 'text',
fields: {
keyword: {
type: 'keyword',
ignore_above: 256
}
}
}
}
};
const room_mapping = {
//similar
};
const asset_mapping = {
//similar
};
const Room = composeWithElastic({
graphqlTypeName: 'RoomType',
elasticIndex: 'rooms',
elasticType: '_doc',
elasticMapping: room_mapping,
elasticClient: new elasticsearch.Client({
host: 'http://localhost:9200',
apiVersion: '7.0'
})
});
const Floor = composeWithElastic({
graphqlTypeName: 'FloorType',
elasticIndex: 'floors',
elasticType: '_doc',
elasticMapping: floor_mapping,
elasticClient: new elasticsearch.Client({
host: 'http://localhost:9200',
apiVersion: '7.0'
})
});
const Asset = composeWithElastic({
graphqlTypeName: 'AssetType',
elasticIndex: 'assets',
elasticType: '_doc',
elasticMapping: asset_mapping,
elasticClient: new elasticsearch.Client({
host: 'http://localhost:9200',
apiVersion: '7.0'
})
});
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
roomSearch: Room.getResolver('search').getFieldConfig(),
roomSearchConnection: Room.getResolver('searchConnection').getFieldConfig(),
elastic70: elasticApiFieldConfig({
host: 'http://localhost:9200',
apiVersion: '7.0'
})
}
})
});
module.default = { schema };
server.js 是这样的:
const graphqlHTTP = require('express-graphql');
const { schema } = require('./schema/schema_es');
// const schema = require('./schema/schema');
var cors = require('cors');
const server = require('express')();
//allow cross-origin
server.use(
'/',
cors(),
graphqlHTTP({
schema: schema,
graphiql: true,
formatError: (error) => ({
message: error.message,
stack: error.stack.split('\n')
})
})
);
const PORT = process.env.PORT || 6060;
server.listen(PORT, () => console.log(`Server started on port ${PORT}`));
我重新启动了服务器,这是我得到的错误
invariant.esm.js:31 [GraphQL error]: Message: GraphQL middleware options must contain a schema., Location: undefined, Path: undefined
我不知道如何使用此方法将 graphql 模式、rootquery..etc 转换为 ES 查询graphql-compose-elasticsearch
,不胜感激!
解决方案
推荐阅读
- python-2.x - 打印后使用 raw_input,未按正确顺序执行
- c# - 向网页发送rabbitmq响应
- github - 如何在 Travis CI 中更改 git clone 步骤的克隆目录
- android - 如何将存储在 recyclerview 适配器中的数组列表转换为字符串?
- eucalyptus - 我需要连接在基于 VMware 的桉树云平台中创建的实例,但我不明白该怎么做?
- racket - Racket 中的高 DPI 支持
- google-maps-api-3 - 谷歌地图 setIcon 更新路径(不是 URL)
- java - Java FX 类无法解析为 Eclipse 2018-12 和 JDK 11.02 的类型
- ibm-watson - Watson Assistant api 中的分页
- terraform - 来自 Terraform on vsphere 的多个 VM