Я использую базу данных 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
за каждый день.
Вот что мне не нравится в этом подходе:
- Запуск отдельного запроса для каждого дня (обычно я смотрю на 30 дней за раз) кажется неправильным; это то, что должно быть сделано на стороне базы данных, а не на стороне приложения.
- База данных также должна выполнять подсчет различных
device
. - Мой сервер настроен на часовой пояс UTC, поэтому, если сейчас после полуночи по UTC, но до полуночи по центральному времени, последняя запись в этом списке всегда будет нулевой. Это достаточно легко исправить, но я бы предпочел достаточно умное решение, чтобы предотвратить это в первую очередь.
- Вся эта функция занимает около 500 мс для запуска. Это не страшно — я единственный, кто запускает запрос, и только один или два раза в день, — но похоже, что операция не должна занимать так много времени.
Есть ли способ добавить больше этой логики в запрос MongoDB?