计算数组的数量和索引

时间:2014-07-24 12:58:47

标签: arrays node.js mongodb mongoose

我有一个对象数组:

 result = [
 { _id: 53d0dfe3c42047c81386df9d, video_id: '1' },
 { _id: 53d0dfe3c42047c81386df9e, video_id: '1' },
 { _id: 53d0dfe3c42047c81386df9f, video_id: '1' },
 { _id: 53d0dfe3c42047c81386dfa0, video_id: '2' },
 { _id: 53d0dfe3c42047c81386dfa1, video_id: '2' },
 { _id: 53d0dfe3c42047c81386dfa2, video_id: '1' },
 { _id: 53d0dfe3c42047c81386dfa3, video_id: '2' },
 { _id: 53d0dfe3c42047c81386dfa4, video_id: '1' } 
 ]

我需要创建另一个数组,它将video_id作为索引,并包含此video_id在第一个数组中出现的次数:

list = [
{'1' : 5},
{'2' : 4}
]

目前,我使用此代码:

while (i < result.length)
{
    if(list[result[i].video_id] === undefined) {
        list[result[i].video_id] = 0;
    }
    list[result[i].video_id] = list[result[i].video_id] + 1;
    i = i + 1;
}

它有效,但我想知道是否有更快更清洁的方法呢? (实际结果数组有超过10k个元素,我怀疑&gt; 10k条件语句是最优的......)。

我正在使用node.js,结果是来自mongoose(mongoDB)查询,我没有看到任何方法通过mongoose本身完成这项工作:

var now = new Date();
//M_logs is a mongoose model
query = M_logs.where('time').gt(new Date(now.getFullYear(), 0, 1).getTime() / 1000).lt(now.getTime() / 1000).select('video_id');

(PS:我想知道这不是更多的Code Review问题,请告诉我,如果我偏离主题,那么我可以移植问题。)

编辑:

回答Juan Carlos Farah:

S_logs =  new mongoose.Schema({

    user_ip : String,
    user_id : String,
    user_agent : String,
    canal_id :  String,
    theme_id :  String,
    video_id :  String,
    osef : String,
    time : Number,
    action: String,
    is_newuser : String,
    operator : String,
    template : String,
    catalogue : String,
    referer : String,
    from : String,
    osef1 : String

});

M_logs = mongoose.model('logs', S_logs);

3 个答案:

答案 0 :(得分:2)

您可以使用聚合框架执行此操作。我的想法是做如下的事情:

  1. 匹配您要查找的文件。根据您当前的查询,我们了解time介于new Date(now.getFullYear(), 0, 1).getTime() / 1000now.getTime() / 1000之间的文档。
  2. video_id对匹配的文件进行分组,并跟踪其数量。
  3. 可选择按_id排序,这与原始video_id相同。
  4. 以下是mongo shell语法:

    var now = new Date();
    
    db.M_logs.aggregate([
        {
            "$match" : {
                "time" : { 
                    "$gt" : new Date(now.getFullYear(), 0, 1).getTime() / 1000,
                    "$lt" : now.getTime() / 1000
                }
            }    
        },
        { 
            "$group" : {
                "_id" : "$video_id",
                "count" : { "$sum" : 1 }
            }
        },
        { 
            "$sort" : { "_id" : 1 }
        }
    ]);
    

    如果这对您有用,您可以使用Mongoose或Node.js驱动程序语法轻松实现它。请注意,聚合框架返回一个游标,您可以迭代该游标来填充数组。

    编辑:

    使用Node.js驱动程序,您可以在回调函数中访问聚合查询的结果。如下:

    ...
    , function(err, result) {
        console.dir(result);
        db.close();                          
    }
    

    请注意,聚合查询的Mongoose语法略有不同。

    示例:

    Model.aggregate([ <QUERY> ]).exec( <CALLBACK> );
    

    有关详细信息,请参阅文档here

答案 1 :(得分:1)

我建议您使用aggregation framework来计算文档数量。它将比迭代所有文档并计算它们快得多。

使用mongoose你可以这样做:

var now = new Date();
var startTime = new Date(now.getFullYear(), 0, 1).getTime() / 1000):
var endTime = now.getTime() / 1000;

M_logs.aggregate([
    // filter the documents you're looking for
    {"$match" : { "time" : {"$gt": startTime, "$lt": endTime}}},
    // group by to get the count for each video_id
    {"$group" : {"_id" : "$video_id", "count" : {"$sum" : 1}}},
    // make the output more explanatory; this part is optional
    {"$project" : { "video_id" : "$_id", "count" : "$count", _id : 0}}
]).exec(function(err, docs){
    if (err) console.err(err);
    console.log(docs);
});

docs的输出将为:

[ { count: 4, video_id: '2' }, { count: 5, video_id: '1' } ]

答案 2 :(得分:0)

使用

var list = {};
result.forEach(function (el) {
    list[el.video_id] = (list[el.video_id] || 0) + 1;
});

结果清单看起来像这样:

var list = {
    '1': 5,
    '2': 4
};