MongoDB/Mongoose查询:获取满足优先级约束的A到B路线
如何查询包含地点A且A的优先级小于地点B的路线文档
场景说明
你的Mongoose Schema定义如下:
const locationSchema = new mongoose.Schema({ "name": { type: String, required: true }, "precedence": { type: Number, required: true }, }); const routeSchema = new mongoose.Schema({ "name": { type: String, required: true }, "locations": [{ type: locationSchema, required: true }], });
需要检索同时包含地点A和B,且A的precedence值小于B的precedence值的路线文档,现有测试数据中仅routeA符合要求。
解决方案:使用MongoDB聚合管道
可以通过聚合管道的$match结合表达式操作符实现,具体代码如下:
const Route = mongoose.model('Route', routeSchema); Route.aggregate([ // 先筛选同时包含A和B的路线,减少后续计算量 { $match: { "locations.name": { $all: ["A", "B"] } } }, // 验证A的precedence是否小于B的precedence { $match: { $expr: { $lt: [ // 获取A对应的precedence值 { $arrayElemAt: ["$locations.precedence", { $indexOfArray: ["$locations.name", "A"] }] }, // 获取B对应的precedence值 { $arrayElemAt: ["$locations.precedence", { $indexOfArray: ["$locations.name", "B"] }] } ] } } } ]).then(result => { console.log(result); // 输出仅包含routeA的结果数组 }).catch(err => { console.error(err); });
代码解释
- 第一个
$match阶段:利用$all操作符筛选出locations数组中同时存在name为"A"和"B"的路线,先过滤掉不符合基础条件的文档,提升查询效率。 - 第二个
$match阶段:$indexOfArray:分别定位"A"和"B"在locations.name数组中的索引位置$arrayElemAt:根据索引取出对应的precedence字段值$lt:比较两个precedence值,判断A的优先级是否小于B的优先级
进阶写法(支持多同名地点场景)
如果路线中可能存在多个同名地点,需要确保存在至少一对A的precedence小于B的precedence,可以用$filter和$anyElementTrue实现更严谨的判断:
Route.aggregate([ { $match: { "locations.name": { $all: ["A", "B"] } } }, { $match: { $expr: { $anyElementTrue: { $map: { input: "$locations", as: "locA", in: { $anyElementTrue: { $map: { input: "$locations", as: "locB", in: { $and: [ { $eq: ["$$locA.name", "A"] }, { $eq: ["$$locB.name", "B"] }, { $lt: ["$$locA.precedence", "$$locB.precedence"] } ] } } } } } } } } } ])
这个写法会遍历所有A和B的组合,只要存在任意一对满足A的优先级低于B,就会被筛选出来,适合存在重复地点的复杂场景。
内容的提问来源于stack exchange,提问作者chirag thapa
相关产品推荐
相关产品推荐

