我在
questionBank
集合中有 1000 个问题(每个问题都是一个文档)。
每个问题都有自己的文档 ID、主题键
(s1, s2, s3, s4, ... ,s10)
和难度键 (easy, medium, hard)
。
我的目标是准确获取其中 15 个问题,以满足以下约束:
s1 to s5
主题提出 2 个问题。我们最多需要来自 s6 to s10
主题的 3 个问题。visitedQuestions
集合,其中他们已经尝试过的所有问题的列表都由文档 ID 存储,因此我们也希望避免使用之前尝试过的问题。result = await QuestionBank.aggregate([
{
$facet: {
easyQuestions: [
{
$match: {
difficulty: "Easy",
...criteriaSet,
},
},
{ $sample: { size: difficultyRanges.easy } },
],
mediumQuestions: [
{
$match: {
difficulty: "Medium",
...criteriaSet,
},
},
{ $sample: { size: difficultyRanges.medium } },
],
hardQuestions: [
{
$match: {
difficulty: "Hard",
...criteriaSet,
},
},
{ $sample: { size: difficultyRanges.hard } },
],
},
},
{
$project: {
questions: {
$concatArrays: [
"$easyQuestions",
"$mediumQuestions",
"$hardQuestions",
],
},
},
},
{
$unwind: "$questions",
},
{
$group: {
_id: "$questions.subTopic",
questions: { $push: "$questions" },
count: { $sum: 1 },
},
},
{
$match: {
$or: SAToicLimits,
},
},
{
$limit: 15,
},
]);
let resres: any = [];
for (let i = 0; i < result.length; i++) {
resres = [...resres, ...result[i].questions];
}
result = resres;
if (result.length === 15) {
break;
}
注意:
SAToicLimits
有科目名称和各自的限制。
最有效的方法是什么?
第一个挑战是获得一组随机问题。为此,您可以按
$toHashedIndexKey
值排序。使用 $dateToString: { date: "$$NOW" }
保证每次调用的顺序都不同(除非在一毫秒内执行多次)。您还可以使用静态值(例如 a
、b
、c
)来获得确定性的随机顺序。
一旦你有了随机的问题顺序,你就可以应用你的约束,例如
{$eq: ["$difficulty", "Medium"]}
和 {$lt: [{$divide: ["$difficultyNo", "$difficultyCount"]}, 0.75]}
这是实现这一目标的第一次尝试:
const visitedQuestions = db.visitedQuestions.find({user: "Shaha"}).toArray().map( x => x._id )
db.collection.aggregate([
{ $match: { _id: { $nin: visitedQuestions } } },
{
$set: {
orderBy: {
$toHashedIndexKey: {
$concat: [
{ $toString: "$_id" },
{ $dateToString: { date: "$$NOW" } } // or a static value for random orders which are deterministic
]
}
}
}
},
{
$setWindowFields: {
partitionBy: "$difficulty",
sortBy: { orderBy: 1 },
output: {
difficultyNo: { $documentNumber: {} },
difficultyCount: { $count: {} }
}
}
},
{
$match: {
$expr: {
$or: [
{ $and: [
{ $eq: [ "$difficulty", "Easy" ] },
{ $lt: [ { $divide: [ "$difficultyNo", "$difficultyCount" ] }, 0.4 ] }
]},
{ $and: [
{ $eq: [ "$difficulty", "Medium" ] },
{ $lt: [ { $divide: [ "$difficultyNo", "$difficultyCount" ] }, 0.75 ] }
]},
{ $and: [
{ $eq: [ "$difficulty", "Hard" ] },
{ $lt: [ { $divide: [ "$difficultyNo", "$difficultyCount" ] }, 0.4 ] }
]}
]
}
}
},
{ $sort: { orderBy: 1 } },
{ $limit: 15 }
])
这不是最终的解决方案,但它指明了前进的方向。添加
{
$setWindowFields: {
partitionBy: "$subject",
sortBy: { orderBy: 1 },
output: {
subjectNo: { $documentNumber: {} }
}
}
}
定义与主题相关的约束。