アプリケーションの分析を追跡するために MongoDB データベースを使用しています。データベースからデータを取得するために、(clj-time と Monger を使用して) Clojure アプリケーションを作成しています。
次のようなレコードを含むコレクションがあります
{"_id": ObjectId(...),
timestamp: ISODate("2013-06-01T15:18:37Z"),
device: "04dbf04b6dc0d0a4fd383967b3dc62f50111e07e"}
それぞれdevice
が私のサービスの異なるユーザーを表します。私がやりたいことは、私が毎日何人の (一意の) ユーザーを持っているかを調べることですが、「日」は特に米国/中央時間帯を指し、夏時間を考慮したいという注意事項があります. $group
(それが要件でなければ、 a のようなことをしてからa を実行できると思います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 では午前 0 時以降、中部時間では午前 0 時より前の場合、このリストの最後のエントリは常にゼロになります。これはパッチを適用するのに十分簡単ですが、そもそもそれを防ぐのに十分なほどスマートなソリューションを望んでいます.
- この関数全体の実行には約 500 ミリ秒かかります。それはひどいことではありません — クエリを実行するのは私だけで、1 日に 1 つか 2 回しかありません — しかし、操作にそれほど時間がかからないように思えます。
このロジックをさらに MongoDB クエリに押し込む方法はありますか?