Javascript 使用dataloader处理ArangoDB中嵌套数据的解析器

Javascript 使用dataloader处理ArangoDB中嵌套数据的解析器,javascript,graphql,arangodb,apollo-server,arangojs,Javascript,Graphql,Arangodb,Apollo Server,Arangojs,我正在ArangoDB上实现一个GraphQLAPI(使用arangojs),我想知道如何为这个非常基本的用例最好地实现dataloader(或类似) 我有两个解析器,具有如下所示的DB查询(这两项工作),第一个解析器获取人员,第二个解析器获取与给定人员相关联的记录对象列表(一对多)。关联使用ArangoDB的边缘集合进行 从'arangojs'导入{Database,aql} 从“lodash/pick”导入pick const db=新数据库('http://127.0.0.1:8529'

我正在ArangoDB上实现一个GraphQLAPI(使用arangojs),我想知道如何为这个非常基本的用例最好地实现
dataloader
(或类似)

我有两个解析器,具有如下所示的DB查询(这两项工作),第一个解析器获取人员,第二个解析器获取与给定人员相关联的记录对象列表(一对多)。关联使用ArangoDB的边缘集合进行

从'arangojs'导入{Database,aql}
从“lodash/pick”导入pick
const db=新数据库('http://127.0.0.1:8529')
db.useBasicAuth('root','')
数据库使用数据库(“U系统”)
//id是自动生成的用户id,在Arango中为`_key`
const fetchPerson=id=>async(解析、拒绝)=>{
试一试{
const cursor=await db.query(aql`返回文档(“PersonTable”,${String(id)})`)
//从光标对象展开结果
const result=wait cursor.next()
返回解析(选择(结果,[''u键','firstName','lastName']))
}捕捉(错误){
退货拒绝(err)
}
}
//id是自动生成的用户id(Arango中的`u key`),通过Person\u HasMany\u records边缘集合与记录关联
const fetchRecords=id=>async(解析、拒绝)=>{
试一试{
const edgeCollection=await db.collection('Person\u有许多记录')
//查询只是说:`在edgeCollection中,从原始节点向外一步获取所有连接的节点`
const cursor=await db.query(aql`
记录在案
出站文档(“PersonTable”,${String(id)})
${edgeCollection}
返回记录`)
返回resolve(cursor.map)(每个=>
选择(每个,[“关键”、“介绍”、“标题”、“杂项]))
)
}捕捉(错误){
退货拒绝(err)
}
}
导出默认值{
查询:{
getPerson:({id})=>newpromise(fetchPerson(id)),
getRecords:({ownerId})=>newpromise(fetchRecords(ownerId)),
}

}
因此,dataloader的真正好处在于它可以阻止您执行n+1查询。例如,如果在您的模式中,一个人有一个字段记录,然后您要求输入前10个人的10条记录。在一个简单的gql模式中,这将导致11个请求被触发:前10个人1个请求,然后每个记录一个请求

在dataloader实现后,您可以将其减少为两个请求:一个用于前10个人,另一个用于前10个人的所有记录

对于上面的模式,您似乎无法从dataloader中获得任何好处,因为不可能有n+1查询。如果您在一个请求中对同一个人或记录发出多个请求,那么您可能获得的唯一好处就是缓存(根据您的模式设计,这同样是不可能的,除非您使用批处理查询)

假设您想要缓存。然后你可以这样做:

// loaders.js
// The callback functions take a list of keys and return a list of values to
// hydrate those keys, in order, with `null` for any value that cannot be hydrated
export default {
  personLoader: new DataLoader(loadBatchedPersons),
  personRecordsLoader: new DataLoader(loadBatchedPersonRecords),
};
然后,您希望将加载程序连接到您的服务器,以便于共享。阿波罗文档中的修改示例:

// app.js
import loaders from './loaders';
app.use(
  '/graphql',
  bodyParser.json(),
  graphqlExpress(req => {
    return {
      schema: myGraphQLSchema,
      context: {
        loaders,
      },
    };
  }),
);
然后,您可以在解析器中的上下文中使用它们:

// ViewerType.js:
// Some parent type, such as `viewer` often
{
  person: {
    type: PersonType,
    resolve: async (viewer, args, context, info) => context.loaders.personLoader,
  },
  records: {
    type: new GraphQLList(RecordType), // This could also be a connection
    resolve: async (viewer, args, context, info) => context.loaders.personRecordsLoader;
  },
}

我想我对dataloader的功能感到困惑。提供嵌套数据对我来说确实是个绊脚石

这是丢失的代码。从resolvers.js导出需要一个
person
属性

export default {

    Person: {
        records: (person)=> new Promise(fetchRecords(person._key)),
    },
    Query: {
        getPerson: (_, { id })=> new Promise(fetchPerson(id)),
        getRecords: (_, { ownerId })=> new Promise(fetchRecords(ownerId)),
    },

}
模式中的Person类型需要一个
记录
属性

type Person {
    _key: String!
    firstName: String!
    lastName: String!
    records: [Records]!
}

这些功能似乎是由Apollo
graphql工具提供的

我仍然迷路。我不知道如何返回嵌套在
person
对象中的
记录
数据。请注意,每个查询共享相同的输入:用户id。如果我只需要
person
等属性,那么查询与
person
关联的所有
记录
对象就没有意义了。但是,如果查询包含
person
下的
记录
,则查询该数据并以嵌套结构返回它是有意义的。这是我问题的关键,我该怎么做?