mongodb - MongoDB选择和更新条件复杂
问题描述
一台服务器正在运行多个进程,进程从数据库中读取任务。任务包含状态和_userid,这是用户收集的外部键。看起来像:
{
_userid: ObjectId(),
status: 'waiting',
date: Date()
}
状态可以是:'等待'、'进行中'、'完成'。对于每个用户,我需要按日期排序的任务运行,并且一次只运行一个。如何构建选择一项任务的查询:
- 如果没有“进行中”,则首先选择状态“等待”并将状态更新为“进行中”;
- 如果某事“进行中”,请选择状态为“等待”且不属于任何状态为“进行中”的任务的_userid 的任务(提醒:每个用户一次只有一个)。并且还将状态更新为“进行中”。
这样的查询在 MongoDB 中是否可行?
编辑:例如,我在数据库中有一个任务:
{
_userid: ObjectId(1),
status: 'waiting',
date: Date(1)
},
{
_userid: ObjectId(1),
status: 'waiting',
date: Date(2)
},
{
_userid: ObjectId(2),
status: 'waiting',
date: Date(3)
},
{
_userid: ObjectId(2),
status: 'waiting',
date: Date(4)
}
在这种情况下,应该从任务中选择第一个任务,因为一切都在“等待”。选择第一个任务后,它变为“进行中”:
{
_userid: ObjectId(1),
status: 'in progress',
date: Date(1)
},
{
_userid: ObjectId(1),
status: 'waiting',
date: Date(2)
},
{
_userid: ObjectId(2),
status: 'waiting',
date: Date(3)
},
{
_userid: ObjectId(2),
status: 'waiting',
date: Date(4)
}
现在,应该选择状态为“等待”而不是 _userid:ObjectId(1) 的下一个任务。它将是 ObjectId(2) 和 Date(3)。之后我们有 2 个 _userid 'in progress':ObjectId(1) 和 ObjectId(2),所以下一个请求应该什么也没有收到。
{
_userid: ObjectId(1),
status: 'in progress',
date: Date(1)
},
{
_userid: ObjectId(1),
status: 'waiting',
date: Date(2)
},
{
_userid: ObjectId(2),
status: 'in progress',
date: Date(3)
},
{
_userid: ObjectId(2),
status: 'waiting',
date: Date(4)
}
当第一个任务完成时,它的状态将是“完成”,现在查询必须接收 ObjectId(1) 的第二个任务,因为它的状态是“等待”,并且没有其他任何东西为此 ObjectId(1) 运行。
{
_userid: ObjectId(1),
status: 'finished',
date: Date(1)
},
{
_userid: ObjectId(1),
status: 'in progress',
date: Date(2)
},
{
_userid: ObjectId(2),
status: 'in progress',
date: Date(3)
},
{
_userid: ObjectId(2),
status: 'waiting',
date: Date(4)
}
编辑2:好的,不再相关
解决方案
检查这个:
db.task.aggregate([
{
$sort: {
_userid: 1,
date: 1
}
},
{
$group: {
_id: "$_userid",
task: {
$push: "$$ROOT"
}
}
}
]).forEach(function(doc){
for(var i=0; i<doc.task.length; i++){
//If we want to check if there is any "in progress" for this user
//doc.task.filter(x => x.status == "in progress").length > 0
if(doc.task[i].status == "in progress") {
//Nothing to do
break;
} else if(doc.task[i].status == "waiting") {
//We set i element to in progress
doc.task[i].status = "in progress";
db.task.save(doc.task[i]);
break;
} else if(doc.task[i].status == "finished") {
//We skip this task
continue;
}
}
});
如果您保证“已完成”任务按日期排序,则可以对其进行过滤。
db.task.aggregate([
{
$match: {
status: {
$ne: "finished"
}
}
},
{
$sort: {
_userid: 1,
date: 1
}
},
...
推荐阅读
- r - ggplot:如何选择高于某个阈值但仍显示正确百分比的数据
- google-app-engine - 谁启动了谷歌云调度程序?
- javascript - 为什么“in”不能用于检查特定单词是否在 JavaScript 的数组中
- reactjs - AWS chime 反应没有音频输入
- css - 边框图像源:线性渐变仅读取一种颜色
- javascript - 在 URL 动态更改上重新运行 Firefox 插件的脚本
- powershell - 将 VBScript 代码转换为 Power Shell 代码以将值写入 Windows 10 工作站的 Active Directory 计算机帐户描述
- time-complexity - 使用 ∈ 表示法比较时间复杂度
- angular - Angular - 从 ng-content 访问组件变量
- parameters - 在 CDK 'codepipeline_actions.CloudFormationCreateUpdateStackAction' 中使用部署时间参数