Skip to content

Strapi GraphQL default sort #9465

@stefankainz

Description

@stefankainz

Bug report

Describe the bug

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?

Expected behavior

The GraphQL and REST-API behave the same regarding the sorting.

Code snippets

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,
            ...
        }
    ]
}

System

  • Node.js version: 14.12.0
  • NPM version: 6.14.8
  • Strapi version: 3.4.6
  • Database: sqlite
  • Operating system: Windows 10

Additional context

Reference to stackoverflow: https://stackoverflow.com/questions/66257037/strapi-graphql-default-sort

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions