是否有一种根据特定时区按天分组记录的有效方法?

时间:2013-06-01 18:52:46

标签: mongodb clojure monger clj-time

我正在使用MongoDB数据库来跟踪应用程序的分析。我正在编写一个Clojure应用程序(使用clj-time和Monger)从数据库中获取数据。

我有一个包含

等记录的集合
{"_id": ObjectId(...),
 timestamp: ISODate("2013-06-01T15:18:37Z"),
 device: "04dbf04b6dc0d0a4fd383967b3dc62f50111e07e"}

每个不同的device代表我服务的不同用户。我想要做的是找出我每天有多少(独特的)用户,但需要注意的是,我希望“白天”专门针对美国/中部时区,将夏令时考虑在内。 (如果这不是一项要求,我想我可以做一些像$group然后是distinct的事情。)

以下是我一直在做的事情:

(ns analytics.reporting
  (:use [monger.core :only [connect! connect set-db! get-db]]
        monger.operators
        clj-time.core
        clj-time.periodic
        clj-time.format)
  (:require [monger.collection :as mc]))

(defn to-central
  [dt]
  (from-time-zone dt (time-zone-for-id "America/Chicago")))

(defn count-distinct
  [coll]
  (count (distinct coll)))

(defn daily-usage
  [ndays]
  (let [midnights (map to-central
                       (reverse (for [offset (map days (range ndays))]
                                  (minus (to-central (today-at 0 0)) offset))))
        by-day (for [midnight midnights]
                 (mc/find-maps "devices" {:timestamp {$gte midnight $lt (plus midnight (days 1))}}))
        devices-by-day (map #(map :device %) by-day)
        distinct-devices-by-day (map count-distinct devices-by-day)]
    distinct-devices-by-day))

如果您无法阅读Clojure,这基本上说:获取中心时区中最近的 n 午夜列表,然后运行Mongo查询以查找每个之间的所有记录连续的一对午夜。然后,计算每天内不同device的数量。

以下是我不喜欢这种方法的内容:

  1. 每天运行一个单独的查询(我通常一次看30天)感觉不对;这应该在数据库端而不是应用程序端完成。
  2. 计算不同的device也应由数据库完成。
  3. 我的服务器设置为UTC时区,因此如果它在UTC的午夜之后但在中部时间的午夜之前,则此列表中的最后一个条目将始终为零。这很容易修补,但我更喜欢一个足够智能的解决方案,以防止它首先出现。
  4. 这整个功能大约需要500毫秒才能运行。这并不可怕 - 我是唯一一个运行查询的人,每天只运行一次或两次 - 但似乎操作不应该花那么长时间。
  5. 有没有办法可以将更多的逻辑推入MongoDB查询?

1 个答案:

答案 0 :(得分:1)

正如@WiredPrairie所建议的,当我将其添加到数据库时,我最终只在每条记录中包含了中央时间日期。然后我能够使用一个简单的$group查询来收集每个日期的记录数。