【问题标题】:Mongo Aggregation: Use $count of found documents for queryMongo 聚合:使用 $count 找到的文档进行查询
【发布时间】:2020-07-08 10:21:16
【问题描述】:

我有一个 Mongo 集合 series,其中每个文档都有一个带有 dataPoints 的列表。 具有相同 testStepId 的所有 series 包含相同数量的 dataPoints

{
  "seriesId": {
    "seriesId": "77678ca1-31db-4cec-a042-68a3053b92c6"
  },
  "testStepId": {
    "testStepId": "c152415b-2392-4c2b-af74-51a4973bd257"
  },
  "measurement": {
    "startTime": {
      "$date": "2020-07-07T12:40:49.782Z"
    },
    "endTime": {
      "$date": "2020-07-07T12:42:19.782Z"
    }
  },
  "dataPoints": [
    {
      "timeStamp": {
        "$date": "2020-07-07T12:41:09.782Z"
      },
      "value": "Value_1_1"
    },
    {
      "timeStamp": {
        "$date": "2020-07-07T12:41:29.782Z"
      },
      "value": "Value_1_2"
    },
    {
      "timeStamp": {
        "$date": "2020-07-07T12:41:39.782Z"
      },
      "value": "Value_1_3"
    },
    ...
    {
      "timeStamp": {
        "$date": "2020-07-07T12:42:19.782Z"
      },
      "value": "Value_2_11"
    }
  ]
}

现在我想查询与特定 testStepId 匹配的所有 series 文档(没问题)。 但我不想加载所有找到的 series 中的所有 dataPoints,我只想加载 1000 个 dataPoints。 因此,如果找到 10 个 series,我只需为每个 series 加载 100 个 dataPoints

-> 加载每 (dataPoints.size() / 100) 个数据点

-> 这意味着我必须考虑找到的 series 文档的计数和系列中 dataPoints 的计数

-> 加载每个 X-th dataPoint where

X = 1000 / <count of documents> / <count of dataPoints>

我正在努力通过与MongoDB Compass 的聚合来完成这项工作。但是我仍然无法计算找到的文档并取消此值...

从简单的开始,我只是尝试获取每第二个 dataPoint

{
    project: {
        dataPoints: {
            $map: {
                input: { $range: [ 0, {"$size": "$dataPoints"}, 2 ] },
                as: "index",
                in: { $arrayElemAt: [ "$dataPoints", "$$index" ] }
            }
        }
    }
}

-> 工作正常

现在我想根据找到的文档的数量来获取每个 x-th 'dataPoint' 依赖项。 为此我尝试了一些不同的方法,它们都不起作用......

  1. 尝试:使用 $count 而不是固定数字:
{
    project: {
        dataPoints: {
            $map: {
                input: { $range: [ 0, {"$size": "$dataPoints"}, $count ] },
                as: "index",
                in: { $arrayElemAt: [ "$dataPoints", "$$index" ] }
            }
        }
    }
}

-> “项目规范必须是一个对象”

  1. 尝试:将count定义为变量:
{
    project: {
        dataPoints: {
            $let: {
                vars: { 
                    total: "$count",
                },
                in: { 
                    $map: {
                        input: { $range: [ 0, {"$size": "$dataPoints"}, "$$total"] },
                        as: "index",
                        in: { $arrayElemAt: [ "$dataPoints", "$$index" ] }
                    }
                }
            }
        }
    }   
}

-> "$range 需要一个数值步骤,找到类型的值:missing"

显然我的方法是错误的。 任何人都可以给我一些提示如何让它工作吗?

【问题讨论】:

  • 不应该是X = &lt;count of dataPoints&gt; * &lt;count of documents&gt; / 1000吗?
  • 你是对的,谢谢。

标签: mongodb dictionary count let


【解决方案1】:

我认为X 的公式是X = &lt;count of dataPoints&gt; * &lt;count of documents&gt; / 1000

您不能直接访问特定聚合管道阶段的文档数量(计数)。但是,您可以将所有文档合并到一个文档中并对它们进行计数,然后将它们展开回单独的文档。您可以使用$group$facet 来实现此目的。

我会用$group展示一个例子

[
  {
    $group: {
      _id: null,
      count: { $sum: 1 },
      all: { $push: "$$ROOT" }
    }
  },
  {
    $unwind: "$all"
  },
  {
    $replaceWith: { // $replaceWith is available from v4.2, for earlier version use { $replaceRoot: { newRoot: <doc> } }
      $mergeObjects: [
        "$all",
        {
          dataPoints: {
            $map: {
              input: {
                $range: [
                  0,
                  { $size: "$all.dataPoints" },
                  {
                    $ceil: {
                      $divide: [
                        {
                          $multiply: [
                            { "$size": "$all.dataPoints" },
                            "$count"
                          ]
                        },
                        1000
                      ]
                    }
                  }
                ]
              },
              as: "index",
              in: { $arrayElemAt: ["$all.dataPoints", "$$index"] }
            }
          }
        }
      ]
    }
  }
]

Mongo Playground

【讨论】:

  • 非常感谢,我正朝着这个方向前进。到目前为止还不知道 Mongo Playground ...
  • 别忘了用正确的公式更新问题。如果您认为答案有用,请随意投票或接受答案。
【解决方案2】:

在 mongo 专家的支持下找到了一个非常好的解决方案:

[{
    //
    // Group the series
    //
    '$group': {
        '_id': {
            'seriesName': '$series.seriesName'
        }, 
        'dataPoints': {
            '$push': '$dataPoints'
        }, 
        'series': {
            '$addToSet': '$series'
        }
    }
}, 
{
    //
    // Concat the dataPoints for each series into on array
    //
    '$addFields': {
        'dataPoints': {
            '$reduce': {
                'input': '$dataPoints', 
                'initialValue': [], 
                'in': {
                    '$concatArrays': [
                        '$$value', '$$this'
                    ]
                }
            }
        }
    }
}, 
{
    //
    // Calculate 'x' for 'find every x-th dataPoint' (called index here)
    // 
    '$replaceWith': {
        'dataPoints': {
            '$map': {
                'input': {
                    '$range': [
                        0, {
                            '$size': '$dataPoints'
                        }, {
                            '$ceil': {
                                '$divide': [
                                    {
                                        '$size': '$dataPoints'
                                    }, 100
                                ]
                            }
                        }
                    ]
                }, 
                'as': 'index', 
                'in': {
                    '$arrayElemAt': [
                        '$dataPoints', '$$index'
                    ]
                }
            }
        }
    }
}]

提示:这不会返回数据点的确切数量,而是一个接近度。但这正是我需要的......

MongoPlayground

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-23
    • 2019-10-14
    • 1970-01-01
    • 2019-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多