我有以下模特:
问题模型
var OptionSchema = new Schema({
correct : {type:Boolean, default:false}
value : String
});
var QuestionSchema = new Schema({
value : String
, choices : [OptionSchema]
, quiz : {type:ObjectId, ref:'quizzes'}
, createdOn : {type:Date, default:Date.now}
...
});
var Question = mongoose.model('questions', QuestionSchema);
测验模型
var QuizSchema = new Schema({
name : String
, questions : [{type:ObjectId, ref:'questions'}]
,company : {type:ObjectId, ref:'companies'}
...
});
var Quiz = mongoose.model('quizzes', QuizSchema);
公司模式
var CompanySchema = new Schema({
name :String
...
});
我希望每个查询对每个问题的choices
进行随机播放,我按照以下方式进行操作:
shuffle = function(v){
//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/array/shuffle [rev. #1]
for(var j, x, i = v.length; i; j = parseInt(Math.random() * i), x = v[--i], v[i] = v[j], v[j] = x);
return v;
};
app.get('/api/companies/:companyId/quizzes', function(req, res){
var Query = Quiz.find({company:req.params.companyId});
Query.populate('questions');
Query.exec(function(err, docs){
docs.forEach(function(doc) {
doc.questions.forEach(function(question) {
question.choices = shuffle(question.choices);
})
});
res.json(docs);
});
});
我的问题是:
我可以将choices
数组随机化而不循环浏览所有文档吗?正如我现在所做的那样?
答案 0 :(得分:0)
问题的实质归结为"我可以随机播放结果并让MongoDB为我做这项工作吗?"。嗯,是的,你可以,但重要的是要记住,"填充"不再是你的朋友帮助你这样做了,你需要完成自己做的工作。
这个问题的一小部分是我们将要切换到#34;你的客户方" shuffle" mapReduce是为了处理"选择"在服务器上。只是为了踢,我添加了一种技术来改变你的问题"以及:
var Query = Quiz.findOne({ company: "5382a58bb7ea27c9301aa9df" });
Query.populate('company', 'name -_id');
Query.exec(function(err,quiz) {
var shuffle = function(v) {
for(var j, x, i = v.length; i; j = parseInt(Math.random() * i), x = v[--i], v[i] = v[j], v[j] = x);
};
if (err)
throw err;
var raw = quiz.toObject();
shuffle( raw.questions );
Question.mapReduce(
{
map: function() {
shuffle( this.choices );
var found = -1;
for ( var n=0; n<inputs.length; n++ ) {
if ( this._id.toString() == inputs[n].toString() ) {
found = n;
break;
}
}
emit( found, this );
},
reduce: function() {},
scope: { inputs: raw.questions, shuffle: shuffle },
query: { "_id": { "$in": raw.questions } }
},
function(err,results) {
if (err)
throw err;
raw.questions = results.map(function(x) {
return x.value;
});
console.log( JSON.stringify( raw, undefined, 4 ) );
}
);
});
所以这个的关键部分不是允许&#34;填充&#34;要将所有相关的问题信息提取到您的架构对象中,您正在使用mapReduce进行手动替换。
请注意&#34;架构文档&#34;必须转换为普通对象,这是由.toObject()
调用在那里完成的,以便我们可以替换&#34;问题&#34;与某些与模式类型不匹配的东西。
我们给mapReduce一个查询,通过简单地传入&#34;问题&#34;来从模型中选择所需的问题。数组作为匹配_id
的参数。真的没有什么直接不同于什么&#34;填充&#34;在幕后为你做的,只是我们要处理&#34;合并&#34;手动
&#34; shuffle&#34;函数现在在服务器上执行,因为它被声明为var
,我们可以通过&#34;范围&#34;和&#34;选项&#34;轻松传入。数组在发出之前将被洗牌,并最终返回。
我说的其他可选项是我们也是&#34;洗牌&#34;问题,这只是通过调用&#34; shuffle&#34;只考虑&#34;问题&#34;的_id
值数组,然后将其传递到&#34;范围&#34;。注意到这也是通过$in
传递给查询的,但仅此一项并不能保证返回订单。
这里使用的技巧是mapReduce在&#34; map&#34;阶段,必须&#34;发出&#34;所有键按升序排列到后期。因此,通过将当前_id
值与其位置的位置作为&#34;输入&#34;的索引值进行比较。从范围的数组然后有一个位置顺序,可以作为&#34;键&#34;这里要尊重已经完成的洗牌的顺序。
&#34;合并&#34;然后很简单,因为我们只是替换&#34;问题&#34;使用mapReduce返回的值的数组。这里的.map()
数组函数有一些帮助,可以清除mapReduce返回内容的结果。
除了您的&#34;选项&#34;现在实际上是在服务器上而不是通过循环进行洗牌,这应该可以让您了解如何自定义填充&#34;用于其他功能,例如&#34;切片&#34;和&#34;分页&#34;引用的数组&#34;问题&#34;如果这是其他你可能想看的东西。
答案 1 :(得分:0)
shuffle = function(v){
//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/array/shuffle [rev. #1]
for(var j, x, i = v.length; i; j = parseInt(Math.random() * i), x = v[--i], v[i] = v[j], v[j] = x);
return v;
};
app.get('/api/companies/:companyId/quizzes', function(req, res){
var Query = Quiz.find({company:req.params.companyId});
Query.populate('questions');
Query.exec(function(err, docs){
var raw = docs.toObject();
//shuffle choices
raw.questions.map(el => shuffle(el.choices))
//if you need to shuffle the questions too
shuffle(raw.questions);
//if you need to limit the output questions, especially when ouput questions needs to be a subset of a pool of questions
raw.questions.splice(limit);
res.json(raw); // output quiz with shuffled questions and answers
});
});