【问题标题】:Need to find the most frequently occurring value of a field in a aggregate需要找到聚合中某个字段出现频率最高的值
【发布时间】:2015-11-16 13:30:06
【问题描述】:

从每小时返回一条记录的 MongoDB 聚合中,我还需要知道“模式”或字段中最常出现的值。

到目前为止,我已经选择了两个日期之间的记录集,并且每小时返回一条记录,包括字段值的平均值。但我还需要最常见的类别,其中类别编号字段包含 1、2、3 或 4。

var myName = "CollectionName"
//schema for mongoose
var mySchema = new Schema({
    dt: Date,
    value: Number,
    category: Number
});

var myDB = mongoose.createConnection('mongodb://localhost:27017/MYDB');

myDBObj = myDB.model(myName, evalSchema, myName);

以下 $group 中的日期数学为一天中的每个小时创建一条记录,$avg 平均价格字段....

但我不知道如何在类别字段中返回最频繁出现的 1、2、3 或 4...没有 $mode 聚合运算符,我收到错误 "exception: unknown group operator '$mode'"

myDBObj.aggregate([
        {
            $match: { "dt": { $gt: new Date("October 13, 2010 12:00:00"), $lt: new Date("November 13, 2010 12:00:00") } }
        },{
            $group:  {
            "_id": {
                "dt": {
                    "$add": [
                        {
                            "$subtract": [
                                { "$subtract": ["$dt", new Date(0)] },
                                {
                                    "$mod": [
                                        { "$subtract": ["$dt", new Date(0)] },
                                        3600000//1000 * 60 * 60
                                    ]
                                }
                            ]
                        },
                        new Date(0)
                    ]
                }
            }, 
            "price": { "$avg": "$price" },
            "category" : { "$mode" : "$category"}
        }
        }], function (err, data) { if (err) { return next(err); } res.json(data); });

有没有办法返回字段中包含的最常见值?

我需要使用 map-reduce 函数吗?我如何将它们与上面的每小时聚合结合起来?感谢您的帮助。

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    你不能只是“弥补”。运算符 as $mode 不是聚合运算符,您唯一可以使用的是 those that actually exist

    因此,为了返回分组时间段内出现次数最多的类别值,有必要首先对每个值进行分组并返回出现次数。然后您可以按该计数对这些结果进行排序,并返回记录该期间内计数最高的类别值:

        // Filter dates
        { "$match": { 
            "dt": { 
                "$gt": new Date("October 13, 2010 12:00:00"), 
                "$lt": new Date("November 13, 2010 12:00:00")
            } 
        }},
    
        // Group by hour and category, with avg and count
        { "$group": {
            "_id": {
                "dt": {
                    "$add": [
                        {
                            "$subtract": [
                                { "$subtract": ["$dt", new Date(0)] },
                                {
                                    "$mod": [
                                        { "$subtract": ["$dt", new Date(0)] },
                                        3600000//1000 * 60 * 60
                                    ]
                                }
                            ]
                        },
                        new Date(0)
                    ]
                },
                "category": "$category"
            }, 
            "price": { "$avg": "$price" },
            "count": { "$sum": 1 }
        }},
        // Sort on date and count
        { "$sort": { "_id.dt": 1, "count": -1 }},
    
        // Group on just the date, keeping the avg and the first category
        { "$group": {
            "_id": "$_id.dt",
            "price": { "$avg": "$price"}
            "category": { "$first": "$_id.category" }
        }}
    

    所以$group 在日期和类别上,并通过$sum 保留类别计数。然后你$sort 所以最大的“计数”在每个分组日期的顶部。最后,当您应用另一个仅应用于日期本身的 $group 时,使用 $first,以便返回每个日期计数最多的类别。

    不要被$max 这样的运营商所诱惑,因为它们在这里不起作用。关键区别在于为每个类别值生成的“记录/文档”的“绑定”关系。因此,不是您想要的最大“计数”或最大“类别”值,而是“产生”最大计数的类别值。因此这里需要$sort

    最后一些你“应该”打破的习惯:

    • 除非您真的知道自己在做什么,否则不要使用非 UTC 格式的日期实例数据作为输入。日期将始终转换为 UTC,因此至少在测试列表中,您应该习惯以这种方式指定日期值。

    • 换一种方式可能看起来更干净一些,但像1000 * 60 * 60 这样的东西比3600000 更能描述它正在做什么。相同的值,但一种形式是一目了然的时间单位。

    • 当只有一个值时复合 _id 也会混淆问题。因此,如果这是唯一存在的值,那么访问 _id.dt 毫无意义。当_id 中有多个属性时,就可以了。但是单个值应该只分配给_id。否则一无所获,单身很清楚。

    【讨论】:

    • 我在周末花了很多时间尝试不同的东西,这真的很棒,谢谢你,我也把你的习惯放在船上。我对为什么 $avg : price 执行两次感到有些困惑。是因为第一个分组为每个小时和类别创建子组吗?在排序之后,这些子组的平均值也需要平均..嗯..啊好吧。为了确定,我必须查看每个阶段的输出形式。感谢您的宝贵帮助
    猜你喜欢
    • 2012-11-03
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    • 2011-05-07
    相关资源
    最近更新 更多