【问题标题】:MongoDB MapReduce update in place how toMongoDB MapReduce 更新到位如何
【发布时间】:2011-08-16 19:38:10
【问题描述】:

*基本上我正在尝试按过去一小时内的分数对对象进行排序。

我正在尝试为我的数据库中的对象生成每小时投票总和。投票嵌入到每个对象中。对象架构如下所示:

{
    _id: ObjectId
    score: int
    hourly-score: int <- need to update this value so I can order by it
    recently-voted: boolean
    votes: {
        "4e4634821dff6f103c040000": { <- Key is __toString of voter ObjectId
            "_id": ObjectId("4e4634821dff6f103c040000"), <- Voter ObjectId
            "a": 1, <- Vote amount
            "ca": ISODate("2011-08-16T00:01:34.975Z"), <- Created at MongoDate
            "ts": 1313452894 <- Created at timestamp
        },
        ... repeat ...
    }
}

这个问题其实和我前两天问的一个问题Best way to model a voting system in MongoDB有关

我将如何(我可以?)运行 MapReduce 命令来执行以下操作:

  1. 仅在最近投票 = true 或每小时得分 > 0 的对象上运行。
  2. 计算过去一小时内创建的投票总和。
  3. 更新每小时得分 = 上面计算的总和,最近投票 = 假。

我还阅读了here,我可以通过在 M/R 命令之前运行 db.getMongo().setSlaveOk() 在从属数据库上执行 MapReduce。我可以在从属设备上运行 reduce 并更新主数据库吗?

是否可以使用 Mongo MapReduce 进行就地更新?

【问题讨论】:

    标签: mapreduce mongodb


    【解决方案1】:

    你绝对可以做到这一点。我会一次解决一个问题:

    1。 您可以指定一个查询以及您的 map-reduce,它过滤将传递到 map 阶段的对象集。在 mongo shell 中,这看起来像(假设 mr 分别是你的 mapper 和 reducer 函数的名称):

    > db.coll.mapReduce(m, r, {query: {$or: [{"recently-voted": true}, {"hourly-score": {$gt: 0}}]}})
    

    2。 第 1 步将允许您在过去一小时内至少有一次投票(或 recently-voted 设置为 true)的所有文档上使用映射器,但并非所有投票都在最后一小时内。因此,您需要在映射器中过滤列表,并仅发出您希望计算的选票:

    function m() {
      var hour_ago = new Date() - 3600000;
      this.votes.forEach(function (vote) {
        if (vote.ts > hour_ago) {
          emit(/* your key */, this.vote.a);
        }
      });
    }
    

    并减少:

    function r(key, values) {
      var sum = 0;
      values.forEach(function(value) { sum += value; });
      return sum;
    }
    

    3。 要更新每小时分数表,您可以使用reduceOutput 选项来映射-reduce,这将使用发出的值和输出集合中先前保存的值(如果有)调用您的reducer。该遍的结果将保存到输出集合中。这看起来像:

    > db.coll.mapReduce(m, r, {query: ..., out: {reduce: "output_coll"}})
    

    除了重新减少输出之外,您还可以使用merge,它将用新创建的文档覆盖输出集合中的文档(但留下与您创建的_ids 不同的_id 的任何文档) m-r job),replace,这实际上是一个 drop-and-create 操作并且是默认值,或者使用{inline: 1},它将结果直接返回给 shell 或你的驱动程序。请注意,使用 {inline: 1} 时,您的结果必须适合单个文档允许的大小(最近的 MongoDB 版本为 16MB)。

    (4.) 您可以在辅助节点(“从节点”)上运行 map-reduce 作业,但由于辅助节点不能接受写入(这就是使它们成为辅助节点的原因),因此您只能在使用内联输出时执行此操作。

    【讨论】:

    • 好的,在第 3 步之前一切都有意义。我不太明白如何获取减少的每小时得分总和并更新集合中的相关对象。假设我们有一个集合 cmets 与我的问题中的模式,我想将所有相关的评论每小时分数更新为新的减少总和。 Hourly-score 是评论对象的参数,而不是单独集合中的参数。我该怎么做?
    • 哦,我明白了——您想将hourly-score 字段更新为带有map-reduce 输出的投票金额的总和(字段votes.a)?我不认为你可以在 map-reduce 中执行此操作,但你绝对可以做一个后处理步骤,使用 map-reduce 输出来更新你想要的任何集合。
    • 嗯好的。从关系数据库来看,这是一项相当简单的任务。基本上我想做的就是在过去一个小时内按分数对对象进行排序。在关系中,我会将分数保存在单独的表中。然后我会从对象表中选择,加入分数表,对过去一小时的分数求和,然后按该总和排序。也许要么。 mongo 根本不适合这个或 b。我错误地组织了我的对象/投票?
    • 我建议使用 cron 脚本运行 map-reduce,然后立即使用其输出更新初始表。
    • 是的,我倾向于这样做,至少现在是这样。非常感谢您的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-07
    • 1970-01-01
    • 2016-05-27
    • 1970-01-01
    • 2015-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多