新人求助,关于DataLoader
发布于 7 年前 作者 mjt19930301 4730 次浏览 来自 问答

1.DataLoader 把数据库查询发出时,要求key 和 value 数目是一致的,但是有的时候,其中的子查询有可能查不出数据,整个查询返回的结果集的数量小于key的个数,这样导致DataLoader发生错误,而使整个查询结果都是null,请问有什么解决方法么

2 egg-graphql中有一个写法 .then(user => user.map(u => u.toJSON())) 其中user已经是 Sequelize 查询后返回的结果了,已经是一个Promis 对象了,这样toJSON一下有什么特殊意义么?

11 回复

为什么不自己找答案呢?

var DataLoader = require('dataloader');
var nano = require('nano');

var couch = nano('http://localhost:5984');

var userDB = couch.use('users');
var userLoader = new DataLoader(keys => new Promise((resolve, reject) => {
  userDB.fetch({ keys: keys }, (error, docs) => {
    if (error) {
      return reject(error);
    }
    resolve(docs.rows.map(row => row.error ? new Error(row.error) : row.doc));
  });
}));

// Usage

var promise1 = userLoader.load('8fce1902834ac6458e9886fa7f89c0ef');
var promise2 = userLoader.load('00a271787f89c0ef2e10e88a0c00048b');

Promise.all([ promise1, promise2 ]).then(([ user1, user2]) => {
  console.log(user1, user2);
});

key 只是缓存的对象的一个唯一 ID 而已,dataloader 就是一个缓存队列而已,跟函数式编程的缓存比较类似,只要参数是一直的,那么结果就是一直的。 Promse<SequelizeInstance> 和 Promise<Object> 能一样么,一个是返回 sequelize model 实例,一个是放回原生对象。

dataloader 其实全是存在 js 内的。

 if (shouldCache) {
      this._promiseCache.set(cacheKey, promise);
    }

_promiseCache 是一个 map。数据量太大,还是建议使用 redis。

因为它这个是多个的 key ,为了支持 loadMany ,所以,在 sequelize 中用 $in ,即 where in SQL

子查询不建议3层以上吧,特殊需求,再次通过 GraphQL 请求就是了。

GraphQL 服务,好像 github 上面有更好的。

楼主这个问题我也遇到了

@MiYogurt 谢谢您的回答,toJSON懂了,但是dataloader 我和您的看法不一样,我的理解是key并不是为了loadMany; 因为loadMany的实现也是调用load;而在本次的事件循环,是为了把所有的load查询合并归到$in中,再下一次事件循环直接就调用一次数据库查询就能查出所有结果,而key是为了区分各个查询的不同,区分应该返回数据的那一条;而且即便不是三层以上的,也有可能调用同一个load多次,其中只要一个是没查到数据的,整个查询就变成null了

@MiYogurt 本来想用apollo来的,但是比较喜欢egg;感觉省心。。

@MiYogurt

	  var userLoader = new DataLoader(keys => new Promise((resolve, reject) => {
		userDB.fetch({ keys: keys }, (error, docs) => {
		  if (error) {
			return reject(error);
		  }
		  resolve(docs.rows.map(row => row.error ? new Error(row.error) : row.doc));
		});
	  }));

问题出在keys是五个,但是其中有一个查不出数据,返回的docs结果集是4个

		 var batchPromise = batchLoadFn(keys);
		  if (!batchPromise || typeof batchPromise.then !== ‘function’) {
	  return failedDispatch(loader, queue, new TypeError(
		'DataLoader must be constructed with a function which accepts ’ +
		'Array<key> and returns Promise<Array<value>>, but the function did ’ +
		not return a Promise: ${String(batchPromise)}.
	  ));
	}

其中就有一个key对应的结果不存在,导致错误,但是查询得到的结果集并不受我控制,我也不能给查不到的加个站位的 promise。。。

没有,本来就是空,你自己要加一个 Error 在里面。 我说的是 Prisma。https://www.prismagraphql.com/

@MiYogurt 感谢安利。我去研究研究

“子查询有可能查不出数据”,为了保证 keys 数组和返回数组长度一直,需要子查询返回 null。所以需要这样写:

function fetch(ids) {
   const list = await this.ctx.model.User.findAll({ id: ids });
   return ids.map(id => _.find(list, { id }));
}
回到顶部