Strapi GraphQL default sort

System Information
  • Strapi Version: 3.4.6
  • Operating System: Windows 10
  • Database: sqlite
  • Node Version: 14.12.0
  • NPM Version: 6.14.8

Hi,
I’m using Strapi Version 3.4.6 with a mutation “generateQuiz” to generate a quiz with a set of random questions from a pool of questions. In the controller I query all questions (inefficient, I know, but thats ok for the moment), shuffle the questions and pick the first x questions from the randomized list. When the questionpool contains less than x questions I would expect to get a quiz with a randomly sorted list of all available questions. Thats the case when I query the REST-API, but not when I query the GraphQL-API. GraphQL returns a quiz with questions always sorted by their ID.

Sample: Let’s assume we have a question pool of 9 questions (IDs 1 to 9) and we want to generate a quiz with a maximum of 10 questions. In the generateQuiz controller following happens:

  1. Query all (9) questions from the database
  2. Shuffle them
  3. take 10 out of the 9 questions -> results in still 9 questions
  4. create a new quiz with the questions
  5. return

When I call the REST-API I get a quiz with the following list of questions for example: [5,3,2,8,6,1,4,9,7]

When I call the GraphQL-API I get always a quiz with a sorted list of the questions: [1,2,3,4,5,6,7,8,9]

Why is this the case? And can I change this behaviour?

Code

controller code:

    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 query:

mutation {
  generateQuiz(questionCount: 15) {
    id
    questions {
      id
    }
  }
}

sample console output:

[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 query result:

{
  "data": {
    "generateQuiz": {
      "id": "91",
      "questions": [
        {
          "id": "1"
        },
        {
          "id": "2"
        },
        {
          "id": "3"
        },
        {
          "id": "4"
        },
        {
          "id": "5"
        },
        {
          "id": "6"
        },
        {
          "id": "7"
        },
        {
          "id": "8"
        },
        {
          "id": "9"
        }
      ]
    }
  }
}

api result (removed unnecessary data):

{
    "id": 88,
    ...
    "questions": [
        {
            "id": 5,
            ...
        },
        {
            "id": 3,
            ...
        },
        {
            "id": 2,
            ...
        },
        {
            "id": 8,
            ...
        },
        {
            "id": 6,
            ...
        },
        {
            "id": 1,
            ...
        },
        {
            "id": 4,
            ...
        },
        {
            "id": 9,
            ...
        },
        {
            "id": 7,
            ...
        }
    ]
}

References:

BR, Stefan