子数组上的mongodb mapreduce

esyap4oy  于 2021-06-02  发布在  Hadoop
关注(0)|答案(1)|浏览(365)

我在网上搜索了很长时间,但找不到解决这个问题的办法。虽然有很多map reduce示例,但我还是很困惑,因为我的文档有一个属性,它是一个对象数组。
我很确定这对有经验的人来说应该很容易,但我现在是个笨蛋。
我有一份文件大概是这样的

{
    _id:guid,
    clientId:guid,
    reference:'abc123'
    items:
    [
        { _id:guid, category:'A', length:100, active:true },
        { _id:guid, category:'B', length:150, active:true },
        { _id:guid, category:'A', length:10, active:false },
        { _id:guid, category:'A', length:111, active:true },
     ]
}

我想产生这个结果

dateFromIdGuid(day) category countOfItems countOfActive sumOfLength

我希望以这种格式保存数据,以减少写入操作的次数(每秒对该集合的写入已超过1000次,而且还在不断增加)
这让我发疯,所以任何帮助都将非常感谢。
谢谢。

iyr7buue

iyr7buue1#

如果您正在讨论从guid中提取时间戳并将其减少为离散的一天,那么mongodb在这方面对您不会有太大帮助。您需要一个外部语言实现来支持这样一个函数,并实现一个外部mapreduce进程,比如hadoop。
这让我想知道,如果我们真的在谈论一个guid,或者你真的是指一个guid ObjectID 这将是 _id 字段,除非该字段已被特别重写以在其中包含guid。
即使不是这样,您也可以通过在文档中添加某种类型的“timestamp”字段并使用正确的bson date对象类型来获得帮助,如下所示:

{
    _id:guid,
    "timestamp": ISODate("2014-05-27T00:00:00Z")
    "clientId":guid,
    "reference":'abc123'
    "items":
    [
        { _id:guid, category:'A', length:100, active:true },
        { _id:guid, category:'B', length:150, active:true },
        { _id:guid, category:'A', length:10, active:false },
        { _id:guid, category:'A', length:111, active:true },
     ]
}

这允许您使用mongodb聚合框架,因为它可以对这种类型的日期对象进行操作,以便将结果分解为离散的几天:

db.collection.aggregate([
    { "$unwind": "$items" },
    { "$group": {
        "_id": { 
            "day": { "$dayOfYear": "$timestamp" },
            "category": "$items.category"
        },
        "countOfItems": { "$sum": 1 },
        "countOfActive": {
            "$sum": {
                "$cond": [
                    "$items.active",
                    1,
                    0
                ]
            }
        },
        "sumOfLength": { "$sum": "$items.length" }
    }} 
])

这不仅能以mongodb最快的方式给出结果,而且“timestamp”值对于过滤日期范围内的查询也很有用,这是从其他值很难做到的。
mongodbmapreduce提供的javascript中还有一种方法允许您从 ObejctId . 但这比聚合框架运行得慢:

db.collection.mapReduce(
    function() {
        var date = this._id.getTimestamp();
        items.forEach(function(item) {
            var day = 
                "" + date.getFullyear() + 
                "" + ( date.getMonth() + 1 ) +
                "" + date.getDate();
            emit(
                {
                    day: day,
                    category: item.category
                },
                {
                    countOfItems: 1,
                    countOfActive: ( item.active ) ? 1 : 0,
                    sumOfLength: item.length
                }
            );
       });
    },
    function( key, values ) {
        var reduced = {
            countOfItems: 0,
            countOfActive: 0,
            sumOfLength: 0
        };
        values.forEach(function(value) {
            for ( var k in value ) {
                reduced[k] += value[k];
            }
        });
        return reduced;
    },
    { 
        "out": { "inline": 1 }
    }
)

这与Map器分解数组并提供分组键的情况基本相同,而reducer只是对Map器中的值求和。因此,即使您必须从guid中提取,当您使用hadoop时,guid会为java等语言中的Map器和缩减器提供基本布局。
查看aggregate和mapreduce手册页面,了解有关可以应用的选项的更多信息。

相关问题