最近在学习 基金投资,作为搞技术的,肯定不可能止步于了解皮毛知识。所以写了一个程序,去爬取基金的一些数据,然后用MongoDB做数据分析

昨天在分析采集的数据时,遇到一个场景,我想统计某一只基金的历史净值数据,看哪些基金的数据比较全面。

我的数据存储结构是这样的:

{
    "_id" : ObjectId("5d048672f241304ded366682"),
    "fund_code" : "110023",
    "updated_at" : ISODate("2019-06-15T05:47:30.000Z"),
    "created_at" : ISODate("2019-06-15T05:47:30.000Z"),
    "day_net_info" : [ 
        {
            "date" : "20140102",
            "net" : 1.328,
            "sum" : 1.328
        }, 
        {
            "date" : "20150105",
            "net" : 1.269,
            "sum" : 1.269
        }, 
        {
            "date" : "20140103",
            "net" : 1.324,
            "sum" : 1.324
        }]
}

上面结构中,每天的基金净值数据都存在 day_net_info 这个字段中,所以上面的统计需求,转化为编程需求就是:按MongoDB按某个字段(数组)长度排序,取出数据最全的前十只基金。

我的实现方式是这样的:

db.fund_daynet.aggregate([
    {$unwind: '$day_net_info'},
    {$group: {_id: '$_id',day_net_info: {$push: '$day_net_info'},cnt: {$sum: 1}}},
    {$sort: {cnt:-1}},
    {$limit: 10}
])

最终确实实现了,但是效率还是很低的。2010年到现在将近十年的基金净值数据,使用 unwind 平铺转化后,有400多万条数据,再分组和统计,计算后最终的得出结果的时间比较长,目前没有找到更好的解决方案。

================

2019-06-17 改良方法

周六解决这个问题的时候比较着急,回头我想了一下,还真有个方法可以统计元素个数,所以改良方法如下:

db.fund_daynet.aggregate([
    {$project:{fund_code:1, cnt:{$size:'$day_net_info'}}},
    {$sort: {cnt:-1}},
    {$limit: 10}
])

这个方法的原理是使用 $size 方法统计元素个数,然后把返回值作为 $sort 的参数进行排序,执行速度就比之前的方法快多了。

本文为 陈华 原创,欢迎转载,但请注明出处:http://www.ichenhua.cn/blog/post/45