我正在研究一个项目,在该项目中,用户可以对一场比赛下注,如果他为获胜的团队下注,则可以赚取积分。
我正在建立一个排行榜,需要从平台中选择50个最佳玩家(得分最高的玩家)。
处理点动态地迫使我查看聚合方法,以便根据这些Models
计算用户点:
const UserSchema = new mongoose.Schema({
admin: { type: Boolean, default: true },
username: String,
password: String,
pronos: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Prono', default: [] }],
});
const PronoSchema = new mongoose.Schema({
match: { type: mongoose.Schema.Types.ObjectId, ref: 'Match' },
local: Number,
guest: Number,
coeff: Number,
});
const StepSchema = new mongoose.Schema({
matchs: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Match', default: [] }],
name: String,
});
const CompetitionSchema = new mongoose.Schema({
steps: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Step', default: [] }],
start: { type: mongoose.Schema.Types.Date },
name: String,
});
const MatchSchema = new mongoose.Schema({
local: { type: mongoose.Schema.Types.ObjectId, ref: 'Team' },
guest: { type: mongoose.Schema.Types.ObjectId, ref: 'Team' },
localScore: { type: Number, default: -1 },
guestScore: { type: Number, default: -1 },
date: { type: mongoose.Schema.Types.Date },
});
总结所有这些代码:
玩家在pronos
上的Matches
上下注,称为Steps
,下注在Competition
内。因此,比赛的每一步都有自己的比赛。
我一直在制作这个游戏来计算玩家的积分,我想知道我是否朝着正确的方向前进
const users = await User.aggregate([
{ $unwind: '$pronos' },
{
$lookup: {
from: 'pronos',
localField: 'pronos',
foreignField: '_id',
as: 'pronoObjects',
}
},
{ $unwind: '$pronoObjects' },
{
$lookup: {
from: 'matches',
localField: 'pronoObjects.match',
foreignField: '_id',
as: 'matches',
}
},
{ $unwind: '$matches' },
{
$addFields: {
pointsEarned: {
$switch: {
branches: [
{
case: {
$and: [
{ $eq: ['$pronoObjects.local', '$matches.localScore'] },
{ $eq: ['$pronoObjects.guest', '$matches.guestScore'] },
],
},
then: 3,
},
{
case: {
$and: [
{ $lt: [{ $subtract: ['$pronoObjects.local', '$pronoObjects.guest'] }, 0] },
{ $lt: [{ $subtract: ['$matches.localScore', '$matches.guestScore'] }, 0] }
]
},
then: 1,
},
{
case: {
$and: [
{ $gt: [{ $subtract: ['$pronoObjects.local', '$pronoObjects.guest'] }, 0] },
{ $gt: [{ $subtract: ['$matches.localScore', '$matches.guestScore'] }, 0] }
]
},
then: 1,
},
],
default: 0,
}
}
}
},
{
$group: {
_id: '$_id',
points: { $sum: '$pointsEarned' }
}
},
{
$lookup: {
from: 'users',
localField: '_id',
foreignField: '_id',
as: 'user',
}
}
]);
由于它按照我想要的方式工作,因此我计划通过Competition
建立一个排名,用户可以在其中选择比赛ID并查看其排名。
当试图实现这一目标时,我一直在使用许多放松方法,以至于在分组之前我的响应时间为1万行。因此,我想知道是否有人可以向我暗示实现此目标的正确方法。
我不是要寻找完整的答案,我是mongo的新手,并且想了解良好做法或学习新的汇总方法。
谢谢。
编辑:
通过这种汇总,我设法为每个用户获取积分。问题在于,只有2位用户才能进行400次比赛,而这需要10秒钟以上的时间。 我想念什么吗?
这是我使用的请求:
return await Competition.aggregate([
{
$match: {
$expr: {
$eq: ['$_id', { $toObjectId: compId }],
}
}
},
{ $unwind: '$steps' },
{
$lookup: {
from: 'steps',
as: 'stepsObject',
localField: 'steps',
foreignField: '_id',
}
},
{ $unwind: '$stepsObject' },
{ $unwind: '$stepsObject.matchs' },
{
$project: {
_id: 1,
stepsObject: 1,
}
},
{
$lookup: {
from: 'matches',
as: 'matchesObject',
let: { otherid: '$stepsObject.matchs' },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $eq: ['$$otherid', '$_id'] },
{ $ne: ['$localScore', -1] },
]
}
}
}
],
},
},
{ $unwind: '$matchesObject' },
{
$lookup: {
from: 'users',
as: 'users',
pipeline: [
{
$project: {
_id: 1,
pronos: 1,
}
}
],
}
},
{ $unwind: '$users' },
{ $unwind: '$users.pronos' },
{
$lookup: {
from: 'pronos',
as: 'pronosObject',
let: { matchid: '$matchesObject._id', knownpronos: '$users.pronos' },
pipeline: [
{
$match: {
$expr:
{
$and: [
{ $eq: ['$$matchid', '$match'], },
{ $eq: ['$$knownpronos', '$_id'] },
]
}
}
}
]
// localField: 'users.pronos',
// foreignField: '_id',
}
},
{ $unwind: '$pronosObject' },
{
$addFields: {
pointsEarned: {
$switch: {
branches: [
{
case: {
$and: [
{ $eq: ['$pronosObject.local', '$matchesObject.localScore'] },
{ $eq: ['$pronosObject.guest', '$matchesObject.guestScore'] },
],
},
then: { $multiply: [3, '$pronosObject.coeff'] },
},
{
case: {
$and: [
{ $lt: [{ $subtract: ['$pronosObject.local', '$pronosObject.guest'] }, 0] },
{ $lt: [{ $subtract: ['$matchesObject.localScore', '$matchesObject.guestScore'] }, 0] }
]
},
then: { $multiply: [1, '$pronosObject.coeff'] },
},
{
case: {
$and: [
{ $gt: [{ $subtract: ['$pronosObject.local', '$pronosObject.guest'] }, 0] },
{ $gt: [{ $subtract: ['$matchesObject.localScore', '$matchesObject.guestScore'] }, 0] }
]
},
then: { $multiply: [1, '$pronosObject.coeff'] },
},
],
default: 0,
}
}
}
},
{
$group: {
_id: '$users._id',
pointsEarned: { $sum: '$pointsEarned' },
}
}
]);
编辑2:
我用另一种方法更快地重写了整个管道。我仍然有一个小问题。如果我摆脱了最后一组,则该请求只需要4毫秒即可运行,但是通过id对点进行分组的最后一组则需要花费550ms的时间。我不知道该如何优化,因为这是每个用户所有积分的最终加法。
这是我随附的:
return await Competition.aggregate([
{
$match: {
$expr: {
$eq: ['$_id', { $toObjectId: compId }],
}
}
},
{ $unwind: '$steps' },
{
$lookup: {
from: 'steps',
as: 'stepsObject',
localField: 'steps',
foreignField: '_id',
}
},
{ $unwind: '$stepsObject' },
{
$project: {
_id: 1,
stepsObject: 1,
}
},
{
$lookup: {
from: 'matches',
as: 'matchesObject',
let: { otherid: '$stepsObject.matchs' },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $in: ['$_id', '$$otherid'] },
{ $ne: ['$localScore', -1] },
]
}
}
}
],
},
},
{
$lookup: {
from: 'users',
as: 'users',
pipeline: [
{
$project: {
_id: 1,
pronos: 1,
}
}
],
}
},
{ $unwind: '$users' },
{ $unwind: '$users.pronos' },
{
$lookup: {
from: 'pronos',
as: 'pronosObject',
localField: 'users.pronos',
foreignField: '_id',
}
},
{ $unwind: '$pronosObject' },
{
$project: {
user_id: '$users._id',
pronosObject: 1,
matchesObjects: {
$arrayElemAt: [
{
$filter: {
input: '$matchesObject',
as: 'matchesObjects',
cond: { $eq: ['$$matchesObjects._id', '$pronosObject.match'] }
}
}, 0
]
},
}
},
{
$addFields: {
pointsEarned: {
$switch: {
branches: [
{
case: {
$and: [
{ $eq: ['$pronosObject.local', '$matchesObjects.localScore'] },
{ $eq: ['$pronosObject.guest', '$matchesObjects.guestScore'] },
],
},
then: { $multiply: [3, '$pronosObject.coeff'] },
},
{
case: {
$and: [
{ $lt: [{ $subtract: ['$pronosObject.local', '$pronosObject.guest'] }, 0] },
{ $lt: [{ $subtract: ['$matchesObjects.localScore', '$matchesObjects.guestScore'] }, 0] }
]
},
then: { $multiply: [1, '$pronosObject.coeff'] },
},
{
case: {
$and: [
{ $gt: [{ $subtract: ['$pronosObject.local', '$pronosObject.guest'] }, 0] },
{ $gt: [{ $subtract: ['$matchesObjects.localScore', '$matchesObjects.guestScore'] }, 0] }
]
},
then: { $multiply: [1, '$pronosObject.coeff'] },
},
],
default: 0,
}
}
}
},
{
$group: { // This is causing me trouble
_id: '$user_id',
pointsEarned: { $sum: '$pointsEarned' },
}
}
]);