MongoDB使用$switch分支判断子数组isPass状态更新索引问题
MongoDB findOneAndUpdate 中通过 $switch 实现数组元素状态判断逻辑
已定义的 Mongoose Schema
const mongoose = require("mongoose"); const uniqueValidator = require("mongoose-unique-validator"); const Schema = mongoose.Schema; const stepsSchema = new Schema({ oid: { type: String }, wid: { type: String }, tid: { type: String }, flow: {type: Object}, actionFlow: [[{id: {type:String}, isPass: {type: Boolean}}]], // 类似输入状态管理的运行逻辑 stepHistory: [{type:String}], currentStepIndex: {type: Number} }) stepsSchema.plugin(uniqueValidator); stepsSchema.index({tid: 1}) module.exports = mongoose.model("Steps", stepsSchema);
需求与待完善代码
需要在findOneAndUpdate操作中,通过$switch分支实现以下逻辑:
- 当
actionFlow[currentStepIndex]对应的子数组内所有isPass字段均为true时,递增currentStepIndex - 当所有
isPass均为false时,递减该值 - 其余情况保持原值
当前待完善的查询代码如下:
steps = await Steps.findOneAndUpdate( { tid: tid }, [{ $set: { currentStepIndex: { $switch: { branches: [ { case: { arrayElemAt: [`actionFlow`, `$currentStepIndex`] /* 需要补充判断所有isPass为true的逻辑 */}, then: 10, }, { case: { arrayElemAt: [`actionFlow`, `$currentStepIndex`] /* 需要补充判断所有isPass为false的逻辑 */}, then: -10, }, ], default: '$currentStepElement', // 这里应为$currentStepIndex,属于笔误 }, }, } }],
完善后的代码
结合MongoDB的$allElementsTrue、$map等操作符,可实现所需判断逻辑,最终代码如下:
steps = await Steps.findOneAndUpdate( { tid: tid }, [ { $set: { currentStepIndex: { $switch: { branches: [ // 情况1:当前子数组所有isPass均为true,递增索引 { case: { $allElementsTrue: { $map: { input: { $arrayElemAt: ["$actionFlow", "$currentStepIndex"] }, as: "item", in: "$$item.isPass" } } }, then: { $add: ["$currentStepIndex", 1] } }, // 情况2:当前子数组所有isPass均为false,递减索引 { case: { $allElementsTrue: { $map: { input: { $arrayElemAt: ["$actionFlow", "$currentStepIndex"] }, as: "item", in: { $not: "$$item.isPass" } } } }, then: { $add: ["$currentStepIndex", -1] } } ], // 其余情况保持原索引值 default: "$currentStepIndex" } } } } ], // 如需返回更新后的文档,需添加该选项 { new: true } );
逻辑说明
判断所有isPass为true:
- 用
$arrayElemAt取出actionFlow中对应currentStepIndex的子数组 - 通过
$map将子数组每个元素映射为isPass字段的值 - 最后用
$allElementsTrue验证映射后的数组是否全为true
- 用
判断所有isPass为false:
- 取出目标子数组后,用
$map将每个元素的isPass取反($not) - 再用
$allElementsTrue验证取反后的数组是否全为true,等价于原数组所有isPass均为false
- 取出目标子数组后,用
默认情况:直接保留原
currentStepIndex的值,同时修正了原代码中的笔误
内容的提问来源于stack exchange,提问作者Michael Ratcliffe
相关产品推荐
相关产品推荐

