MongoDB Map Reduce:需要合并到所有其他匹配条件的文档中的一个文档?

MongoDB Map Reduce:需要合并到所有其他匹配条件的文档中的一个文档?,mongodb,mapreduce,Mongodb,Mapreduce,我甚至不知道用什么术语来问这个问题,但我们开始吧 我有一个集合,我正在使用MapReduce对其执行聚合任务。我不能使用聚合管道,因为我需要在减少开销的同时执行自定义代码 为了使问题更清楚,这一点稍微简化了 我有一个集合,其中每个文档包含一个位置(即网格单元ID)和一个时间片(由该时间片开始处的时间戳表示),并包含诸如“车辆数量”等信息;每个位置可以有数千个这样的文档,每个时间段也可以有几个 此外,对于每个位置,可以存在“时间片”属性为空的文档。它包含关于静态特性等的信息:例如,没有时间戳的数

我甚至不知道用什么术语来问这个问题,但我们开始吧

我有一个集合,我正在使用MapReduce对其执行聚合任务。我不能使用聚合管道,因为我需要在减少开销的同时执行自定义代码

为了使问题更清楚,这一点稍微简化了

  • 我有一个集合,其中每个文档包含一个位置(即网格单元ID)和一个时间片(由该时间片开始处的时间戳表示),并包含诸如“车辆数量”等信息;每个位置可以有数千个这样的文档,每个时间段也可以有几个
  • 此外,对于每个位置,可以存在“时间片”属性为空的文档。它包含关于静态特性等的信息:例如,没有时间戳的数据
我想做的是运行一个MapReduce过程,其中输出文档由位置ID和时间片进行键控,最重要的是,我能够将不定时数据与定时数据结合起来

以下是一些示例输入(在数据方面非常简化,但是
cell\u id
timeslice
值正是我必须处理的):

…以及我希望输入产生的输出(我没有将其拆分为
\u id
,但本质上
单元格id
时间片将是
\u id

[
  {
    "cell_id": 100,
    "timeslice": null,
    "num_vehicles": null,
    "num_residential_units": 30,
    "num_commercial_units": 12
  },
  {
    "cell_id": 100,
    "timeslice": "2019-03-20T00:00:00.000Z",
    "num_vehicles": 10,
    "num_residential_units": 30,
    "num_commercial_units": 12
  },
  {
    "cell_id": 100,
    "timeslice": "2019-03-21T00:00:00.000Z",
    "num_vehicles": 9,
    "num_residential_units": 30,
    "num_commercial_units": 12
  },
  {
    "cell_id": 101,
    "timeslice": null,
    "num_vehicles": null,
    "num_residential_units": 8,
    "num_commercial_units": 1
  },
  {
    "cell_id": 101,
    "timeslice": "2019-03-20T00:00:00.000Z",
    "num_vehicles": 5,
    "num_residential_units": 8,
    "num_commercial_units": 1
  },
  {
    "cell_id": 101,
    "timeslice": "2019-03-21T00:00:00.000Z",
    "num_vehicles": 4,
    "num_residential_units": 8,
    "num_commercial_units": 1
  }
]

如果Emit阶段按位置和时间键出已发出的文档,那么我将所有定时数据正确地放入reduce函数,并且我将自动减少未计时的数据…但是我需要以某种方式将未计时的数据合并到每一个简化的定时数据文档中。在Finalize中是否有这样做的方法e阶段,或者是否有一些巧妙的方法来设置键…?我被难住了。坦率地说,解决方案是否涉及map reduce对我来说并不重要,但它必须在有限的硬件上大规模高效。

您可以尝试类似的方法

下面的查询将抓取非空时间戳行,后跟组以获取聚合值。在获得聚合的文档后,您将加入到同一集合中,以拉入未绑定的行

db.collection.aggregate([
  {"$match":{"timeslice":{"$ne":null}}},
  {"$group":{
      "_id":{"cell_id":"$cell_id","timeslice":"$timeslice"},
      "num_vehicles":{"$sum":"$num_vehicles"}
  }},
  {"$lookup":{
     "from":"collection",
     "localField":"_id.cell_id",
     "foreignField":"cell_id",
     "as":"untimed_doc"
   }},
  {"$unwind":"$untimed_doc"},
  {"$match":{"untimed_doc.timeslice":{"$eq":null}}}
])

以下是一种可能帮助您解决此问题的方法 假设:根据您提供的每个cellid的数据,有一条记录的时间片为空

  • 根据空和非空时间片值筛选数据。这将为您提供两个数据集
  • 在这两个数据集上执行基于Cellid的联接。这将把具有非空时间片的行和具有空时间片的行合并在一起
  • 最后,使用cellid和时间片对联接的数据集进行分组。您可以在每个组上运行reduce,该组的单元格时间片为空。但是,由于此行与其他每行联接,因此您必须在reduce中处理重复项。您可以通过设置一个标记来实现这一点,即您已经使用nu对行进行了说明ll时间片
  • 我在这里附上了一张图片,这可能会帮助你理解我的意思。请注意,为了简单起见,我只显示了CellId和timestamp列


    如果您可以添加示例输入文档、预期结果和任何代码来备份您的文章,这将非常有帮助。@user2683814完成!将基于时间的文档映射到单独的集合,然后使用聚合管道连接回未计时信息的方法是否可行?或者您是否需要未计时信息来重新发布duce-step?不幸的是,正如问题中所提到的,我需要在Reduce阶段执行一些自定义代码;这些代码无法转换为聚合管道操作符,因此聚合管道(至少是单独的)无法运行不行。很抱歉,我可能误解了你文章的最后一部分,认为没有map reduce你也可以。啊——是的,我不喜欢map reduce本身,但这是我能想到的唯一一件可能符合要求的事情。不过,合理地确定聚合管道不会起作用。我恐怕没有map reduce这个问题的解决方案。你正在触及map reduce框架的局限性。我担心可能会出现这种情况,但希望有一些聪明的方法来解决这个问题,我没有考虑过。
    db.collection.aggregate([
      {"$match":{"timeslice":{"$ne":null}}},
      {"$group":{
          "_id":{"cell_id":"$cell_id","timeslice":"$timeslice"},
          "num_vehicles":{"$sum":"$num_vehicles"}
      }},
      {"$lookup":{
         "from":"collection",
         "localField":"_id.cell_id",
         "foreignField":"cell_id",
         "as":"untimed_doc"
       }},
      {"$unwind":"$untimed_doc"},
      {"$match":{"untimed_doc.timeslice":{"$eq":null}}}
    ])