将两个猫鼬聚合管道合并为一个,其中第一个管道的结果用于另一个管道

问题描述 投票:0回答:1

我有一个名为 dummy 的集合。 它的模式定义为 -

const schema = mongoose.Schema(
{
    Name: { type: String },
    start: { type: String },
    end: { type: String },
}

现在我想从

end < x
的集合中获取文档。 但这里有一个问题 -

  1. 从匹配上述过滤器的文档中,我不希望那些
    Name
    的文档我们可以找到另一个文档,其中
    start<=x<=end
    .
  2. 并且每个
    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,然后将其传递到第二个聚合管道中。 那么有什么办法可以实现这个目标吗?

mongodb mongoose mongodb-query aggregation-framework
1个回答
0
投票

我们可以通过计算 4 个辅助字段来实现所需的行为。

  1. isInRange
    :布尔值,表示是否
    start<=x<=end
  2. diffToX
    :数字,表示
    x
    end
    的绝对差值 通过对
    Name
    字段进行分组,我们得到了另外 2 个聚合辅助字段
  3. anyInRange
    :布尔值,通过使用
    $max
    ,我们检查是否有任何
    isInRange
    Name
    组中。如果有任何条目在范围内,则最终结果将为 true;否则就是假的。
  4. rank
    :int,通过排序
    diffToX
    计算排名。末端最接近 X 的条目应具有最高排名(即最小排名数)

通过使用 4 个辅助字段,我们可以通过以下步骤获得您预期的结果:

  1. 计算每个文档的
    isInRange
    diffToX
  2. anyInRange
    rank
     计算 
    $setWindowFields
     中的 
    "partitionBy": "$Name"
    "sortBy": {"diffToX": 1}
  3. $match
    带末端 <= X and anyInRange: false
  4. $sort
    ,等级:1 和
    $limit: 1
    以获得最接近 X
  5. 的条目
db.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"
    ]
  }
])

蒙戈游乐场

© www.soinside.com 2019 - 2024. All rights reserved.