如何使用数据加载器?
How to use dataloader?
我正在想办法解决这个问题。
我想从我的数据库中获取我所有的用户,缓存他们
然后在发出新请求时,我想获取已缓存的请求和已创建的新请求。
到目前为止:
const batchUsers = async ({ user }) => {
const users = await user.findAll({});
return users;
};
const apolloServer = new ApolloServer({
schema,
playground: true,
context: {
userLoader: new DataLoader(() => batchUsers(db)),// not sending keys since Im after all users
},
});
我的解析器:
users: async (obj, args, context, info) => {
return context.userLoader.load();
}
load 方法需要一个参数,但在这种情况下,我不想拥有一个特定的用户,我想要所有的用户。
我不明白如何实现这个,谁能解释一下。
如果您只想加载所有记录,那么开始使用 DataLoader 就没什么意义了。DataLoader 背后的目的是批处理多个调用,例如 load(7)
和 load(22)
到单个调用中,然后针对您的数据源执行。如果您需要获取所有用户,那么您应该直接调用 user.findAll
。
此外,如果您最终使用 DataLoader,请确保您传入的是函数,而不是对象作为上下文。该函数将在每个请求上 运行,这将确保您使用的是 DataLoader 的新实例,而不是具有陈旧缓存的实例。
context: () => ({
userLoader: new DataLoader(async (ids) => {
const users = await User.findAll({
where: { id: ids }
})
// Note that we need to map over the original ids instead of
// just returning the results of User.findAll because the
// length of the returned array needs to match the length of the ids
return ids.map(id => users.find(user => user.id === id) || null)
}),
}),
请注意,如果您希望 load
拒绝,您也可以 return 一个错误实例而不是数组中的 null
。
花了我一段时间,但我开始工作了:
const batchUsers = async (keys, { user }) => {
const users = await user.findAll({
raw: true,
where: {
Id: {
// @ts-ignore
// eslint-disable-next-line no-undef
[op.in]: keys,
},
},
});
const gs = _.groupBy(users, 'Id');
return keys.map(k => gs[k] || []);
};
const apolloServer = new ApolloServer({
schema,
playground: true,
context: () => ({
userLoader: new DataLoader(keys => batchUsers(keys, db)),
}),
});
解析器:
user: {
myUsers: ({ Id }, args, { userLoader }) => {
return userLoader.load(Id);
},
},
操场:
{users
{Id
myUsers
{Id}}
}
游乐场解释:
users 基本上获取所有用户,然后 myusers 通过从第一次调用继承 id 来做同样的事情。
我想我在这里选择了一个糟糕的例子,因为我没有看到它在性能上有任何提升。但是我确实看到查询变成了:
SELECT ... FROM User WhERE ID IN(...)
我正在想办法解决这个问题。
我想从我的数据库中获取我所有的用户,缓存他们 然后在发出新请求时,我想获取已缓存的请求和已创建的新请求。
到目前为止:
const batchUsers = async ({ user }) => {
const users = await user.findAll({});
return users;
};
const apolloServer = new ApolloServer({
schema,
playground: true,
context: {
userLoader: new DataLoader(() => batchUsers(db)),// not sending keys since Im after all users
},
});
我的解析器:
users: async (obj, args, context, info) => {
return context.userLoader.load();
}
load 方法需要一个参数,但在这种情况下,我不想拥有一个特定的用户,我想要所有的用户。
我不明白如何实现这个,谁能解释一下。
如果您只想加载所有记录,那么开始使用 DataLoader 就没什么意义了。DataLoader 背后的目的是批处理多个调用,例如 load(7)
和 load(22)
到单个调用中,然后针对您的数据源执行。如果您需要获取所有用户,那么您应该直接调用 user.findAll
。
此外,如果您最终使用 DataLoader,请确保您传入的是函数,而不是对象作为上下文。该函数将在每个请求上 运行,这将确保您使用的是 DataLoader 的新实例,而不是具有陈旧缓存的实例。
context: () => ({
userLoader: new DataLoader(async (ids) => {
const users = await User.findAll({
where: { id: ids }
})
// Note that we need to map over the original ids instead of
// just returning the results of User.findAll because the
// length of the returned array needs to match the length of the ids
return ids.map(id => users.find(user => user.id === id) || null)
}),
}),
请注意,如果您希望 load
拒绝,您也可以 return 一个错误实例而不是数组中的 null
。
花了我一段时间,但我开始工作了:
const batchUsers = async (keys, { user }) => {
const users = await user.findAll({
raw: true,
where: {
Id: {
// @ts-ignore
// eslint-disable-next-line no-undef
[op.in]: keys,
},
},
});
const gs = _.groupBy(users, 'Id');
return keys.map(k => gs[k] || []);
};
const apolloServer = new ApolloServer({
schema,
playground: true,
context: () => ({
userLoader: new DataLoader(keys => batchUsers(keys, db)),
}),
});
解析器:
user: {
myUsers: ({ Id }, args, { userLoader }) => {
return userLoader.load(Id);
},
},
操场:
{users
{Id
myUsers
{Id}}
}
游乐场解释:
users 基本上获取所有用户,然后 myusers 通过从第一次调用继承 id 来做同样的事情。
我想我在这里选择了一个糟糕的例子,因为我没有看到它在性能上有任何提升。但是我确实看到查询变成了:
SELECT ... FROM User WhERE ID IN(...)