1

この構造を持つコレクションにユーザー ドキュメントがあります。

{ "_id" : ObjectId( "4fb54ef46d93b33b21003951" ),
  "activities" : [ 
    { "id" : ObjectId( "4fd66f9001e7fe9f03000065" ),
      "type" : "checkin",
      "date_time_created" : Date( 1339453328000 )}, 
    { "date_time_created" : Date( 1337351732000 ),
      "date_time_updated" : Date( 1337351952635 ),
      "id" : ObjectId( "4fb65e346d93b3fe77000000" )}
  ]
}

日付に基づいてこれらのドキュメントを簡単にクエリできます。

User.where( 
  :activities => { 
    '$elemMatch' => {
      :date_time_created => { '$gte' => start_date, '$lt' => end_date }
    }
  } 
).length

ログによると:

MOPED: 127.0.0.1:27017 COMMAND database=db command={:count=>"users", :query=>{"activities"=>{"$elemMatch"=>{"date_time_created"=>{"$gte" =>2012-05-10 00:00:00 UTC、"$lt"=>2012-07-12 00:00:00 UTC}}}}} (0.5260ms)

この方法で必要な結果が得られます。

ただし、同じ基準に基づいて新しい集計関数と $match を使用しようとすると、次のようになります。

User.collection.aggregate( [
  { "$match" => {
    :activities => {
      '$elemMatch' => {
        :date_time_created => { '$gte' => start_date, '$lt' => end_date }
      }
    }
  } }
]).length

ログによると:

MOPED: 127.0.0.1:27017 COMMAND database=db command={:aggregate=>"users", :pipeline=>[{"$match"=>{:activities=>{"$elemMatch"=>{"date_time_created" =>{"$gte"=>2012 年 5 月 10 日 (木)、"$lt"=>2012 年 7 月 12 日 (木)}}}}}]} (0.6049ms)

"start_date" と "end_date" は Ruby Date オブジェクトであり、両方のクエリで本質的に同じです。ただし、ログを見ると、さまざまな形式に変更されています。start_date.strftime("%Y-%m-%d") のようなものでフォーマットを強制しようとしても、まだ機能しません。

集約パイプラインには他の関数がありますが、それらを取り出してもエラーが発生します。

集計関数が日付に一致するようにするにはどうすればよいですか?

4

4 に答える 4

7

次のテストでは、集計フレームワークを使用して、クエリの論理的な等価物を概算します。

最初に配列を $unwind し、$match、次に一致する配列要素が複数ある場合は $addToSet を使用して $group します。これは損失の多いプロセスですが、カウントまたは ID のみが必要な場合は許容されます。

これが役立つことを願っています。

テスト/ユニット/user_test.rb

require 'test_helper'

class UserTest < ActiveSupport::TestCase
  def setup
    User.delete_all
  end

  test "user aggregate" do
    User.create(
        activities: [
          { id: Moped::BSON::ObjectId("4fd66f9001e7fe9f03000065"),
            type: "checkin",
            date_time_created: Time.at(1339453328000) },
          { date_time_created: Time.at(1337351732000),
            date_time_updated: Time.at(1337351952635),
            id: Moped::BSON::ObjectId("4fb65e346d93b3fe77000000") }
        ]
    )
    start_date = Time.at(1339453328000)
    end_date = start_date + 24*60*60
    assert_equal(1, User.where(
        :activities => {
            '$elemMatch' => {
                :date_time_created => { '$gte' => start_date, '$lt' => end_date }
            }
        }
    ).length)
    assert_equal(1, User.collection.aggregate( [
        { '$unwind' => '$activities' },
        { '$match' => { '$and' => [
            { 'activities.date_time_created' => { '$gte' => start_date } },
            { 'activities.date_time_created' => { '$lt' => end_date } }
        ] } },
        { '$group' => { '_id' => '$_id', 'activities' => { '$addToSet' =>  '$activities' } } }
    ] ).length)
  end
end
于 2013-01-15T21:06:20.250 に答える
-3

ruby にはあまり興味がありませんが、mongo shell を貼り付けていただけると助かります。

いくつかのヒントがあります: 1. elemMatch を使用しているため、$unwind を使用する必要があります。 2. その後、$match を使用してみてください。

于 2012-12-10T13:22:55.913 に答える