Keystone.js中通过updatedBy实体获取用户信息问题求助
搞定你的KeystoneJS用户关联问题!
嘿,你遇到的这个问题其实是典型的异步操作执行顺序踩坑——你在forEach里调用的User.model.findById()是异步请求,而外层的next(err)根本不等这些请求完成就直接执行了,导致你在外部访问element.userDetails的时候,这些值还没来得及被赋值,自然就是undefined啦。
问题出在哪?
你原来的代码里,forEach循环发起一堆异步查询,但这些查询还没返回结果,你就直接调用next(err)结束了init钩子,这时候locals.data.posts里的userDetails还没被设置,外部自然拿不到值。
修复方案
我们可以用Promise.all()来统一等待所有用户查询完成,确保所有userDetails都赋值好之后再调用next。修改后的代码如下:
view.on('init', function (next) { var q = keystone.list('Post').paginate({ page: req.query.page || 1, perPage: 5, //maxPages: 10, // filters: { // state: 'published', // }, }) .sort('-publishedDate') .populate('author categories'); if (locals.data.category) { q.where('categories').in([locals.data.category]); } q.exec(function (err, results) { if (err) return next(err); // 先处理文章查询的错误 locals.data.posts = results; // 把每个用户查询转换成Promise,方便统一等待 const userFetchPromises = locals.data.posts.results.map(post => { return User.model.findById(post.updatedBy).exec() .then(user => { // 给当前文章赋值用户详情 post.userDetails = `Dr. ${user.name.first}${user.name.last}`; return post; }); }); // 等待所有用户查询完成 Promise.all(userFetchPromises) .then(updatedPosts => { // 更新posts数组为已经赋值好用户详情的版本 locals.data.posts.results = updatedPosts; next(); // 所有准备工作完成,继续下一步 }) .catch(fetchErr => { next(fetchErr); // 捕获用户查询中的错误并传递 }); }); });
核心改动说明
- 把
forEach换成map,将每个用户查询包装成Promise,这样就能用Promise.all()监听所有异步操作的完成状态 - 只有当所有用户数据都查询完成、
userDetails都赋值完毕后,才调用next(),确保外部访问时数据已经准备妥当 - 完善了错误处理,不管是文章查询还是用户查询的错误,都能正确传递给Keystone的钩子处理
这样修改后,你再去访问locals.data.posts.results里的userDetails,就能拿到你想要的用户关联数据啦!
内容的提问来源于stack exchange,提问作者vam
相关产品推荐
相关产品推荐

