1

I need to retrieve from a collection of random docs based on a limit given. If some filters are provided they should be added to filter the results of the response. I'm able to build the match and size based on the fields provided but even tho I have 20 documents that meet the filter when I make the call I receive only 2 or 3 docs back and I can't seem to figure it out. If I set only the limit it does give me back N random docs based on the limit but if I add a filter it won't give me the wanted results.

This is what I do now

const limit = Number(req.query.limit || 1);

  const difficulty = req.query.difficulty;
  const category = req.query.category;
  const settings = [
    {
      $sample: {
        size: limit
      }
    }
  ];

  if (difficulty && category) {
    settings.push({
      $match: {
        difficulty: difficulty,
        category: category
      }
    });
  } else if (difficulty && category == null) {
    settings.push({
      $match: {
        difficulty
      }
    });
  }

  if (difficulty == null && category) {
    settings.push({
      $match: {
        category
      }
    });
  }
  console.log(settings);

  Question.aggregate(settings)
    .then(docs => {
      const response = {
        count: docs.length,
        difficulty: difficulty ? difficulty : "random",
        questions:
          docs.length > 0
            ? docs.map(question => {
                return {
                  _id: question._id,
                  question: question.question,
                  answers: question.answers,
                  difficulty: question.difficulty,
                  category: question.category,
                  request: {
                    type: "GET",
                    url:
                      req.protocol +
                      "://" +
                      req.get("host") +
                      "/questions/" +
                      question._id
                  }
                };
              })
            : {
                message: "No results found"
              }
      };

      res.status(200).json(response);
    })
    .catch(err => {
      res.status(500).json({
        error: err
      });
    });

1 Answer 1

1

Order of the stages matters here. You are pushing the $match stage after the $sample stage which first put the $size to whole the documents and then applies the $match stage on the $sampled documents documents.

So finally you need to push the $sample stage after the $match stage. The order should be

const limit = Number(req.query.limit || 1);

  const difficulty = req.query.difficulty;
  const category = req.query.category;
  const settings = []

  if (difficulty && category) {
    settings.push({
      $match: {
        difficulty: difficulty,
        category: category
      }
    })
  } else if (difficulty && category == null) {
    settings.push({
      $match: {
        difficulty
      }
    })
  }

  if (difficulty == null && category) {
    settings.push({
      $match: {
        category
      }
    })
  }

  setting.push({
    $sample: {
      size: limit
    }
  })
  console.log(settings);

  Question.aggregate(settings)
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you I don't know this but makes total sense!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.