Я сделал демонстрацию, использует lodash.memoize
для решения вопроса N + 1
.
Вот мой запрос: 10 сообщений принадлежит 1 пользователю. И на стороне клиента GraphQL
запрос выглядит так:
query {
posts{
postId
postTitle
postAuthor{
userId
userNme
userEmail
}
}
}
Если не использовать dataloader
или какую-либо функцию напоминания, он отправит 11 (10 + 1) запросов в базу данных. 1 временный запрос для posts
, 10 временных запросов для пользователя каждого сообщения.
constructor() {
super();
this.userLoader = this.createLoader(this.findByIds.bind(this));
this.userLoaderLodash = _.memoize(this.findByIds.bind(this));
}
public async findByIds(ids: string[]) {
return this.db('users').whereIn('user_id', ids);
}
public async findById(id: string) {
this.ids.push(id);
// return new Promise((resolve, reject) => {
// process.nextTick(() => {
return this.userLoaderLodash(this.ids).then((users: any[]) => {
// resolve(_.first(users));
return _.first(users);
});
// });
// }).then((user) => {
// this.ids = [];
// return user;
// });
// return this.userLoader.load(id);
}
this.userLoader
- это dataloader
, this.userLoaderLodash
реализуется lodash.memoize
.
Вот журналы отладки базы данных:
{ method: 'raw',
sql: '\n SELECT * FROM posts;\n ',
bindings: [],
options: {},
__knexQueryUid: '046167c1-35d7-427f-8f3d-d4ac203670a6' }
{ method: 'select',
options: {},
timeout: false,
cancelOnTimeout: false,
bindings: [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
__knexQueryUid: '450f19b7-3841-4c08-81f0-ca740f3abcf9',
sql: 'select * from "users" where "user_id" in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' }
Как вы можете видеть, способ использования lodash.memoize
также может решить проблему с запросом N + 1
. Не использовать process.nextTick
, кажется, не влияет на результаты.