在日期范围内计数不同

时间:2016-07-13 17:12:30

标签: mongodb mongodb-query pymongo aggregation-framework

我有一个包含site-events集合的MongoDB数据库。文件看起来像:

{ 
    "_id" : ObjectId("5785bb02eac0636f1dc07023"), 
    "referrer" : "https://example.com",
    "_t" : ISODate("2016-07-12T18:10:17Z"),
    "_p" : "ucd7+hvjpacuhtgbq1caps4rqepvwzuoxm=", 
    "_n" : "visited site", 
    "km screen resolution" : "1680x1050" 
},

{ 
    "_id" : ObjectId("5785bb02eac0636f1dc07047"), 
    "url" : "https://www.example.com/", 
    "referrer" : "Direct", 
    "_t" : ISODate("2016-07-12T18:10:49Z"), 
    "_p" : "txt6t1siuingcgo483aabmses2et5uqk0=", 
    "_n" : "visited site", 
    "km screen resolution" : "1366x768" 
},

{ 
    "_id" : ObjectId("5785bb02eac0636f1dc07053"), 
    "url" : "https://www.example.com/", 
    "referrer" : "Direct", 
    "_t" : ISODate("2016-07-12T18:10:56Z"), 
    "_p" : "gcama1az5jxa74wa6o9r4v/3k+zulciqiu=", 
    "_n" : "visited site", 
    "km screen resolution" : "1366x768" 
}

我想了解一个日期范围内的独特人物。在SQL中它将是

SELECT COUNT(DISTINCT(`_p`)) FROM collection WHERE `_t` > '<SOME DATE>' AND `_t` <= '<SOME OTHER DATE>'

到目前为止,我已经使用聚合管道对日期进行了分组:

db.siteEvents.aggregate(

[
    { 
        $match : {"_n": "visited site"}
    },

    {   
        $group : {

            _id: {
            year : { $year : "$_t" },        
            month : { $month : "$_t" },        
            day : { $dayOfMonth : "$_t" },
            _p : "$_p"
        },

        count: { $sum: 1 }

        }
    }, 

    {
        $group : {

            _id : {
            year : { $year : "$_id.year" },        
            month : { $month : "$_id.month" },        
            day : { $dayOfMonth : "$_id.day" }
            },

            count: { $sum: 1 }
        }
    }
]

);

但这会产生错误 - 我相信因为第二次分组_id试图抓住一个中间场。我目前只使用Mongo shell,但如果我不得不选择一个替代驱动程序,它将是PyMongo。我想让它在shell中工作(所以我可以理解这个过程)。

2 个答案:

答案 0 :(得分:4)

使用聚合管道,它可能看起来像

db.getCollection('siteEvents').aggregate([
    {
        $match: {
            _t: {
                $gt: ISODate("2016-07-11T08:10:17.000Z"),
                $lt: ISODate("2016-07-12T14:10:17.000Z")
            }
        }
    },
    {
        $group: {
            _id: "$_p"
        }
    },
    {
        $group: {
            _id: null,
            distinctCount: { $sum: 1 }
        }
    }
])

如果您知道结果不同的值不会很大,那么您可以使用简单的查询

db.getCollection('siteEvents').distinct(
    '_p',
    { 
        _t: {
            $gt: ISODate("2016-07-11T08:10:17.000Z"),
            $lt: ISODate("2016-07-12T14:10:17.000Z")
        }
    }).length

答案 1 :(得分:0)

您可以使用$addToSet阶段中的$group运算符返回一个不同的&#34; _p&#34;值然后$project结果文档返回数组的大小,这只是非重复计数。

db.siteEvents.aggregate(
    [
        {"$match": {"_n": "visited site", "_t": {"$gt": <SOME DATE>, "$lt": <SOME OTHER DATE>}}},
        {"$group": {
            "_id": None, 
            "_p_values": {"$addToSet": "$_p"} 
        }}, 
        {"$project": {"_id": 0, "count": {"$size": "$_p_values"}}} 
    ]   
)

对于小尺寸集合,您只需使用distinct,但需要传入查询参数。

len(db.siteEvents.distinct("_p", {"_n": "visited site", "_t": {"$gt": <SOME DATE>, "$lt": <SOME OTHER DATE>}}))