我有一个名为 dummy 的集合。 它的模式定义为 -
const schema = mongoose.Schema(
{
Name: { type: String },
start: { type: String },
end: { type: String },
}
现在我想从
end < x
的集合中获取文档。
但这里有一个问题 -
Name
的文档我们可以找到另一个文档,其中 start<=x<=end
.Name
只能获取一个文档,其中 end 最接近 x。我可以在多个聚合管道中实现此目的,方法是获取第一个聚合管道中
Name
中的所有 namesArr
,其中 start<=x<=end
,然后使用 {$nin:namesArr}
删除具有此类名称的文档,然后按 Name
分组并插入所有文档按降序排序,并选择第一个,以便为每个总线仅获取一个文档,其中 end 最接近第二个聚合管道中的 x。
示例集合-
{Name : 'a', start :30, end :35},
{Name : 'a', start :40, end :50},
{Name : 'b', start :10, end :25},
{Name : 'b', start :30, end :35},
{Name : 'b', start :60, end :80},
因此,如果 x 为 44,则查询应仅返回
{Name : 'b', start :30, end :35}
但我想在单个聚合管道中实现此目的,因为我不想先获取名称Arr,然后将其传递到第二个聚合管道中。 那么有什么办法可以实现这个目标吗?
我们可以通过计算 4 个辅助字段来实现所需的行为。
isInRange
:布尔值,表示是否start<=x<=end
diffToX
:数字,表示x
与end
的绝对差值
通过对 Name
字段进行分组,我们得到了另外 2 个聚合辅助字段anyInRange
:布尔值,通过使用$max
,我们检查是否有任何isInRange
在Name
组中。如果有任何条目在范围内,则最终结果将为 true;否则就是假的。rank
:int,通过排序diffToX
计算排名。末端最接近 X 的条目应具有最高排名(即最小排名数)通过使用 4 个辅助字段,我们可以通过以下步骤获得您预期的结果:
isInRange
和 diffToX
anyInRange
和 rank
计算
$setWindowFields
中的
"partitionBy": "$Name"
和
"sortBy": {"diffToX": 1}
$match
带末端 <= X and anyInRange: false$sort
,等级:1 和 $limit: 1
以获得最接近 Xdb.collection.aggregate([
{
$set: {
isInRange: {
"$cond": {
"if": {
$let: {
vars: {
x: 44
},
in: {
$and: [
{
$lte: [
"$start",
"$$x"
]
},
{
$gte: [
"$end",
"$$x"
]
}
]
}
}
},
"then": true,
"else": false
}
},
diffToX: {
"$abs": {
"$subtract": [
"$end",
44
]
}
}
}
},
{
"$setWindowFields": {
"partitionBy": "$Name",
"sortBy": {
"diffToX": 1
},
"output": {
"anyInRange": {
"$max": "$isInRange"
},
"rank": {
"$rank": {}
}
}
}
},
{
"$match": {
end: {
$lt: 44
},
anyInRange: false
}
},
{
$sort: {
rank: 1
}
},
{
$limit: 1
},
{
"$unset": [
"anyInRange",
"diffToX",
"isInRange",
"rank"
]
}
])