graphql - Strapi GraphQL 默认排序
问题描述
我正在使用带有突变“generateQuiz”的 Strapi 版本 3.4.6 来生成一个带有一组来自问题池的随机问题的测验。在控制器中,我查询所有问题(效率低下,我知道,但目前还可以),随机排列问题并从随机列表中选择前 x 个问题。当问题池包含少于 x 个问题时,我希望得到一个包含所有可用问题的随机排序列表的测验。当我查询 REST-API 时就是这种情况,但当我查询 GraphQL-API 时不是。GraphQL 返回一个测验,其中的问题总是按其 ID 排序。
示例:假设我们有一个包含 9 个问题(ID 1 到 9)的问题库,并且我们希望生成一个最多包含 10 个问题的测验。在 generateQuiz 控制器中发生以下情况:
- 从数据库中查询所有 (9) 个问题
- 洗牌
- 从 9 个问题中取 10 个 -> 结果仍然是 9 个问题
- 用问题创建一个新测验
- 返回
当我调用 REST-API 时,我会收到一个包含以下问题列表的测验:[5,3,2,8,6,1,4,9,7]
当我调用 GraphQL-API 时,我总是得到一个带有问题排序列表的测验:[1,2,3,4,5,6,7,8,9]
为什么会这样?我可以改变这种行为吗?
代码
控制器代码:
async generateQuiz(ctx) {
const {questionCount, includeSubcategories} = ctx.request.body;
const categoryId = ctx.request.body.categoryId ? Number(ctx.request.body.categoryId) : undefined;
const userId = ctx.state.user.id;
let params = {
userId,
// eslint-disable-next-line camelcase
deadline_gte: new Date(),
// eslint-disable-next-line camelcase
finishedAt_null: true,
category: categoryId,
// eslint-disable-next-line camelcase
category_null: categoryId ? undefined : true
};
// remove undefined properties
params = _.pickBy(params, v => v !== undefined);
const quiz = await strapi.services.quiz.findOne(params);
if (quiz) {
throw strapi.errors['badRequest'](`An active quiz with categoryId ${categoryId} already exists. quizId: ${quiz.id}`);
}
let questions;
if (categoryId) {
const searchCategories = await strapi.services.category.list(categoryId, includeSubcategories);
const searchCategoryIds = _.map(searchCategories, 'id');
// eslint-disable-next-line camelcase
questions = await strapi.services['quiz-question'].find({category_in: searchCategoryIds}, []);
}
else {
if (includeSubcategories !== false) {
questions = await strapi.services['quiz-question'].find({}, []);
} else {
throw strapi.errors['badRequest'](`includeSubcategories cannot be set to false when no categoryId is specified`);
}
}
// get question IDs
let questionIds = _.map(questions, 'id');
// shuffle
questionIds = _.shuffle(questionIds);
// take first x question IDs
if (questionCount) {
questionIds = _.take(questionIds, questionCount);
}
strapi.log.debug('questionIds',questionIds);
// get number of questions
const quizQuestionCount = questionIds.length;
const now = _.now();
const deadline = now + (quizQuestionCount * strapi.config.get('server.app.secondsPerQuestionInQuiz', 60) * 1000);
const data = {
startedAt: now,
finishedAt: null,
deadline,
userId,
questions: questionIds,
category: categoryId
};
const newQuiz = await strapi.services.quiz.create(data);
strapi.log.debug('newQuiz question ids', _.map(newQuiz.questions,'id'));
return newQuiz;
},
graphql 查询:
mutation {
generateQuiz(questionCount: 15) {
id
questions {
id
}
}
}
示例控制台输出:
[2021-02-18T08:56:14.622Z] debug questionIds [2,9,1,5,7,6,4,8,3]
[2021-02-18T08:56:14.711Z] debug newQuiz question ids [5,2,6,9,4,8,3,1,7]
graphql 查询结果:
{
"data": {
"generateQuiz": {
"id": "91",
"questions": [
{
"id": "1"
},
{
"id": "2"
},
{
"id": "3"
},
{
"id": "4"
},
{
"id": "5"
},
{
"id": "6"
},
{
"id": "7"
},
{
"id": "8"
},
{
"id": "9"
}
]
}
}
}
api 结果(删除了不必要的数据):
{
"id": 88,
...
"questions": [
{
"id": 5,
...
},
{
"id": 3,
...
},
{
"id": 2,
...
},
{
"id": 8,
...
},
{
"id": 6,
...
},
{
"id": 1,
...
},
{
"id": 4,
...
},
{
"id": 9,
...
},
{
"id": 7,
...
}
]
}
BR,斯特凡
解决方案
推荐阅读
- python - Spyder中的Ipython控制台不使用环境定义的Python版本
- c - 在 C 中测量经过的时间?
- javascript - 如何避免“无效的配置对象。Webpack 已使用与 API 模式不匹配的配置对象进行初始化。”
- r - R:列表到数据框映射功能
- java - 即使指定的模式是点,DecimalFormat 也使用逗号分隔符
- javascript - 如何使用 Angular 9 将多个图像文件和 PDF 文件合并为单个 PDF
- qt - 一次取消选中/选中所有复选框
- java - 如何在 Java 中制作 Material Exposed Drop Down List 必填字段
- salesforce - 内部查询的 SOQL 记录数
- azure - 如何将资源组从禁用的订阅迁移到 Azure 中的工作目录