2016-07-13 11 views
2

Ich habe eine MongoDB-Datenbank mit einer Sammlung von Site-Ereignissen. Die Dokumente sehen so aus:Count Distinct innerhalb des Datumsbereichs

{ 
    "_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" 
} 

Ich möchte eine Anzahl der eindeutigen Personen innerhalb eines Datumsbereichs erhalten. In SQL wäre es

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

Bisher habe ich die Daten gruppiert die Aggregation Pipeline entlang mit:

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 } 
     } 
    } 
] 

); 

Aber das gibt Fehler - ich wegen der zweiten Gruppierung _id versucht zu greifen glauben ein Zwischenfeld. Ich benutze gerade die Mongo-Shell, aber wenn ich einen alternativen Treiber wählen müsste, wäre es PyMongo. Ich möchte das in der Shell arbeiten lassen (damit ich den Prozess verstehen kann).

Antwort

2

Mit einer Aggregation Pipeline es wie so aussehen könnte

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 } 
     } 
    } 
]) 

Wenn Sie die sich daraus ergebenden unterschiedlichen Werte wissen nicht groß sein, dann könnte man ein einfach wie so Abfrage verwenden

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

Können Sie den Zweck der '_id: null' in der letzten Gruppe erklären? Der Rest ist klar - und ich verstehe, wie die Zwischendokumente aussehen. – Jared

+0

Null ist in diesem Fall einfach eine Konstante, Sie können auch jede andere Konstante verwenden, die Sie möchten, z. _id: "MyDistinctCount". Der Zweck besteht lediglich darin, sicherzustellen, dass die Gruppe nur ein einziges Ergebnis produziert, so dass sie die unterschiedlichen Werte der zwischengeschalteten Dokumente zählt. – DAXaholic

0

können Sie Verwenden Sie den Operator $addToSet in der $group Bühne, um ein Array von verschiedenen "_p" -Wert dann $project das resultierende Dokument zurückgeben, um die Größe des Arrays, die nichts anderes als die distinct count ist zurückzugeben.

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"}}} 
    ] 
) 

Zum Sammeln geringer Größe können Sie einfach distinct verwenden, aber Sie müssen in der Abfrage Argumente zu übergeben.

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