Есть ли эффективный способ сгруппировать записи по дням в соответствии с определенным часовым поясом?

Я использую базу данных 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 мс для запуска. Это не страшно — я единственный, кто запускает запрос, и только один или два раза в день, — но похоже, что операция не должна занимать так много времени.

Есть ли способ добавить больше этой логики в запрос MongoDB?


person bdesham    schedule 01.06.2013    source источник
comment
Одним из способов было бы изменить данные, чтобы включить дату в качестве центрального времени. Или вы можете написать MapReduce для расчета итогов. Вы пробовали это?   -  person WiredPrairie    schedule 02.06.2013


Ответы (1)


Как предложил @WiredPrairie, я просто включил дату центрального времени в каждую запись, когда добавил ее в базу данных. Затем я смог использовать тривиальный запрос $group, чтобы собрать количество записей для каждой даты.

person bdesham    schedule 21.06.2013