【发布时间】:2014-08-14 14:20:00
【问题描述】:
我们有一个基本的查询管理工具,用于在我们的管理套件中跟踪一些网站查询,并且我们使用查询集合中每个文档的 ObjectId 来按添加日期对查询进行排序。
{
"_id" : ObjectId("53a007db144ff47be1000003"),
"comments" : "This is a test enquiry. Please ignore. We'll delete it shortly.",
"customer" : {
"name" : "Test Enquiry",
"email" : "test@test.com",
"telephone" : "07890123456",
"mobile" : "07890123456",
"quote" : false,
"valuation" : false
},
"site" : [],
"test" : true,
"updates" : [
{
"_id" : ObjectId("53a007db144ff47be1000001"),
"status" : "New",
"status_id" : ObjectId("537de7c3a5e6e668ffc2335c"),
"status_index" : 100,
"substatus" : "New Web Enquiry",
"substatus_id" : ObjectId("5396bb9fa5e6e668ffc23388"),
"notes" : "New enquiry received from website.",
},
{
"_id" : ObjectId("53a80c977d299cfe91bacf81"),
"status" : "New",
"status_id" : ObjectId("537de7c3a5e6e668ffc2335c"),
"status_index" : 100,
"substatus" : "Attempted Contact",
"substatus_id" : ObjectId("53a80e06a5e6e668ffc2339e"),
"notes" : "In this test, we pretend that we've not managed to get hold of the customer on the first attempt.",
},
{
"_id" : ObjectId("53a80e539b966b8da5c40c36"),
"status" : "Approved",
"status_id" : ObjectId("52e77a49d85e95f00ebf6c72"),
"status_index" : 200,
"substatus" : "Enquiry Confirmed",
"substatus_id" : ObjectId("53901f1ba5e6e668ffc23372"),
"notes" : "In this test, we pretend that we've got hold of the customer after failing to contact them on the first attempt.",
}
]
}
在每个查询中都有一个更新对象数组,这些对象也有一个 ObjectId 作为它们的主要身份字段。我们使用$unwind 和$group 聚合来提取第一个和最新的更新,以及更新的计数,确保我们只在有多个更新的情况下进行查询(因为当更新时自动插入一个查询):
db.enquiries.aggregate([
{
$match: {
"test": true
}
},
{
$unwind: "$updates"
},
{
$group: {
"_id": "$_id",
"latest_update_id": {
$last: "$updates._id"
},
"first_update_id": {
$first: "$updates._id"
},
"update_count": {
$sum: 1
}
}
},
{
$match: {
"update_count": {
$gt: 1
}
}
}
])
这会产生以下输出:
{
"result" : [
{
"_id" : ObjectId("53a295ad122ea80200000005"),
"latest_update_id" : ObjectId("53a80bdc7d299cfe91bacf7e"),
"first_update_id" : ObjectId("53a295ad122ea80200000003"),
"update_count" : 2
},
{
"_id" : ObjectId("53a007db144ff47be1000003"),
"latest_update_id" : ObjectId("53a80e539b966b8da5c40c36"),
"first_update_id" : ObjectId("53a007db144ff47be1000001"),
"update_count" : 3
}
],
"ok" : 1
}
然后将其传递给我们的代码(在本例中为 node.js),我们对其执行一些操作,然后在仪表板上显示一些信息。
理想情况下,我想在查询中添加另一个$group 管道聚合,这将从latest_update_id 的时间戳中减去first_update_id 的时间戳,得到一个时间跨度,然后我们可以使用$avg开。
谁能告诉我这是否可能? (谢谢!)
【问题讨论】:
-
目前不适用于聚合框架。如您所知,您可以从 ObjectId 获取时间戳。因此,要么在客户端代码中执行此操作,要么投降给可以调用该函数以获取时间戳值的 mapReduce。取决于您的输出数据大小。我对聚合管道中的更多“数学”函数投一票。
-
@NeilLunn 使用 MapReduce 不会是世界末日(正如您可能收集到的那样,这主要是一个统计练习),因为我们可以将其安排为一次性 - 它主要是一个问题,看看它是否可能在聚合框架内。如果能够在查询中访问 ObjectId 字段的属性/功能,那就太好了。
-
@abitgone 我很好奇,你会按 _id : null 分组以获得所有文档的平均值吗?
-
@ChristianP:当然,但我需要否定没有 2 个或更多更新的查询。此外,所有文档的平均值是否会以正确保留时间戳的方式作用于 ObjectId 字段?
-
@abitgone 查看我的编辑。我想它会回答你的问题。
标签: mongodb mapreduce timestamp aggregation-framework