SQL に慣れた後、mongoDB でこの問題に遭遇しました。まず、マングースを使用しています。
さて、問題です。という名前のコレクションがありUser
ます。
var UserSchema = new Schema ({
id : ObjectId,
name : {type : String, trim : true, required : true},
email: {type:String, trim:true, required: true, index: { unique: true }},
password: {type:String, required: true, set: passwordToMD5},
age: {type:Number, min: 18, required: true, default: 18},
gender: {type: Number, default:0, required: true},
height: {type: Number, default:180, min: 140, max: 220},
_eye_color: {type: ObjectId, default: null},
location: {
lon: {type: Number, default: 0},
lat: {type: Number, default: 0}
},
status: {type:Number, required: true, default:0}
},{
toObject: { virtuals: true },
toJSON: { virtuals: true },
collection:"user"});
次に、このコレクションからすべてのユーザーを選択し、特別な属性 (「ランク」など) で並べ替える必要があります。このランクは、ポイントからの距離、指定された年齢と比較した年齢などに応じて、特定のロジックで計算されます...
それで、このランクを選択してソートに使用する方法を考えていましたか?仮想フィールドを使用しようとしましたが、追加情報をカウントするのに便利ですが、残念ながらfind()
仮想フィールドで結果を並べ替えることができません。もちろん、このランクを仮想で計算し、すべてのレコードを選択してから、コールバックで JavaScript を実行できます。しかし、この場合、すべてのユーザーを選択して並べ替えてから制限するため、javascript の部分に時間がかかりすぎる可能性があります... mapreduceを使用することを考えていましたが、私が望むようになるかどうかはわかりません。私のタスクがmongoDB/mongooseで実行できる場合、誰かがヒントをくれますか?
編集1
私も集計フレームワークを使用しようとしましたが、最初はそれが機能を備えた最良のソリューションのように思えました$project
。しかし、その後、ランク計算を行う必要が生じたときに、集約が 、 、 などの多くの数学関数をサポートしていないことがわかりsin
ましcos
たsqrt
。また、事前に定義された通常の JavaScript 関数をプロジェクションで使用することもできませんでした。つまり、関数が呼び出されましたが、現在のレコード フィールドを渡すことができませんでした。
{$project: {
distance_from_user: mUtils.getDistance(point, this.location)
}
関数内の 2 番目の属性は「未定義」でした。
したがって、集計フレームワークでランク計算を行うことは不可能だと思います。
EDIT 2 わかりました、リアルタイムクエリには適していないため、mapreduceを使用しないように誰もが私に言っていることは知っていますが、集計を使用できないため、mapreduceを試してみると思います。では、このマップを削減したとしましょう。
function map() {
emit(1, // Or put a GROUP BY key here
{name: this.name, // the field you want stats for
age: this.age,
lat: this.location.lat,
lon: this.location.lon,
distance:0,
rank:0
});
}
function reduce(key, values) {
return val;
}
function finalize(key, value){
return value;
}
var command = {'mapreduce': "user", 'map': map.toString(), 'reduce': reduce.toString(), query:{$and: [{gender: user_params.gender}, {_id: {$ne: current_user_id}}]}, 'out': {inline:1}};
mongoose.connection.db.executeDbCommand(command, function(error, result){
if(error) {
log(error);
return;
}
log(result);
return;
});
すべてのユーザーのランクを計算するには、reduce (または change map) に何を記述すればよいですか?