MongoDB结合组聚合和strLenBytes
Posted
技术标签:
【中文标题】MongoDB结合组聚合和strLenBytes【英文标题】:MongoDB combining group aggregation and strLenBytes 【发布时间】:2018-03-05 14:25:20 【问题描述】:我有一个 Mongo 集合,其中包含这样的文档:
"_id" : ObjectId("5a9d0d44c3a1ce5f14c6940a"),
"topic_id" : "5a7af30613b79405643e7da1",
"value" : "VMware Virtual Platform",
"timestamp" : "2018-03-05 09:26:25.136546",
"insert_ts" : "2018-03-05 09:26:25.136682",
"inserted_by" : 1
,
"_id" : ObjectId("5a9d0d44c3a1ce5f14c69409"),
"topic_id" : "5a7af30713b79479f82b4b84",
"value" : "VMware, Inc.",
"timestamp" : "2018-03-05 09:26:25.118931",
"insert_ts" : "2018-03-05 09:26:25.119081",
"inserted_by" : 1
,
"_id" : ObjectId("5a9d0d44c3a1ce5f14c69408"),
"topic_id" : "5a7af30713b7946d6d0a8772",
"value" : "Phoenix Technologies LTD 6.00 09/21/2015",
"timestamp" : "2018-03-05 09:26:25.101624",
"insert_ts" : "2018-03-05 09:26:25.101972",
"inserted_by" : 1
我想从这个集合中获取一些聚合数据。我想知道最早的时间戳、文档数和所有值的总strlen,但按topic_id分组,其中document-id大于x。
在 mysql 中,我会像这样构建一个 sql:
SELECT
MAX(_id) as max_id,
COUNT(*) as message_count,
MIN(timestamp) as min_timestamp,
LENGTH(GROUP_CONCAT(value)) as size
FROM `dev_topic_data_numeric`
WHERE _id > 22000
GROUP BY topic_id
我如何在 MongoDB 中实现这一点?我已经尝试过构建它,如下所示:
db.getCollection('topic_data_text').aggregate(
[
"$match":
"_id": "$gte": ObjectId("5a9d0aefc3a1ce5f14c68c81")
,
"$group":
"_id": "$topic_id",
"max_id": "$max":"$_id",
"min_timestamp": "$min": "$timestamp",
"message_count": "$sum": 1,
/*"size": "$strLenBytes": "$value" */
]
);
然后我取消注释 $strLenBytes
它崩溃说 strLenBytes 不是组运算符。 API of MongoDB 在这里对我没有帮助。怎么写才能得到strlen?
我的预期结果应该是这样的:
"_id" : "5a7af30613b79405643e7da1",
"max_id" : ObjectId("5a9d0d44c3a1ce5f14c6940a"),
"min_timestamp" : "2018-03-05 09:26:25.136546",
"message_count" : 1,
"size" : 23,
我的 MongoDB 版本是 3.4.4。
【问题讨论】:
你能添加预期的输出吗? 你试过"size": "$sum": "$strLenBytes": "$value"
吗?
@RahulSharma 完成。
@chridam 我检查了你的建议。结果错误显示“无效的运算符 $strLenBytes”
我得到的最接近的结果是使用 "$push":"$value" ...但这并不是我想要得到的结果。
【参考方案1】:
这是因为$strLenBytes
不是累加器,不像$sum
或$max
。 $group
阶段累加值,因此在 $group
阶段有效的任何运算符通常都是累加器。
$strLenBytes
以 1-1 的方式将一个值转换为另一个值。这通常是 $project
阶段的运算符。
在聚合中添加 $project
阶段应该会给您所需的结果。请注意,您还需要稍微修改 $group
阶段以传递所需的值:
> db.test.aggregate([
"$match":
"_id": "$gte": ObjectId("5a9d0aefc3a1ce5f14c68c81")
,
"$group":
"_id": "topic_id": "$topic_id", value: "$value",
"max_id": "$max":"$_id",
"min_timestamp": "$min": "$timestamp",
"message_count": "$sum": 1
,
"$project":
"_id": "$_id.topic_id",
"max_id": "$max_id",
"min_timestamp": "$min_timestamp",
"message_count": "$message_count",
size: "$strLenBytes": "$_id.value"
])
使用您的示例文档输出:
"_id": "5a7af30613b79405643e7da1",
"max_id": ObjectId("5a9d0d44c3a1ce5f14c6940a"),
"min_timestamp": "2018-03-05 09:26:25.136546",
"message_count": 1,
"size": 23
"_id": "5a7af30713b79479f82b4b84",
"max_id": ObjectId("5a9d0d44c3a1ce5f14c69409"),
"min_timestamp": "2018-03-05 09:26:25.118931",
"message_count": 1,
"size": 12
"_id": "5a7af30713b7946d6d0a8772",
"max_id": ObjectId("5a9d0d44c3a1ce5f14c69408"),
"min_timestamp": "2018-03-05 09:26:25.101624",
"message_count": 1,
"size": 40
【讨论】:
谢谢。这解决了我的问题,也帮助我更多地理解了项目阶段。在我看来,该文档缺乏对其用途和如何使用它的更深入的解释。【参考方案2】:在测试了@kevin-adistambha 的答案并进行了一些进一步的实验之后,我找到了另一种方法来实现我想要的结果——也许它有更好的性能——但这需要更多的测试来确定。
db.getCollection('topic_data_text').aggregate(
[
"$match":
"_id": "$gt": ObjectId("5a9f9d8bd5de3ac75f8cc269")
,
"$group":
"_id": "$topic_id",
"max_id": "$max":"$_id",
"min_timestamp": "$min": "$timestamp",
"message_count": "$sum": 1,
"size": "$sum": "$strLenBytes": "$value"
]
);
【讨论】:
聚合管道还针对某些阶段序列进行优化:docs.mongodb.com/manual/core/aggregation-pipeline-optimization以上是关于MongoDB结合组聚合和strLenBytes的主要内容,如果未能解决你的问题,请参考以下文章
MongoDB,如何将查找和排序与聚合中的 $cond 结合起来?