【问题标题】:Mongoid aggregation $match with Date objects not working?Mongoid 聚合 $match 与 Date 对象不起作用?
【发布时间】:2012-11-24 23:45:04
【问题描述】:

我在一个集合中有这样的结构的用户文档:

{ "_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.5260 毫秒)

我通过这种方式得到了我需要的结果。

但是,当我尝试使用新的聚合函数和基于相同条件的 $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.6049 毫秒)

“start_date”和“end_date”是 Ruby Date 对象,在两个查询中基本相同。但是,当我查看日志时,它们会变成不同的格式。当我尝试使用 start_date.strftime("%Y-%m-%d") 之类的东西强制格式时,它仍然不起作用。

聚合管道中还有其他函数,但我把它们取出来仍然报错。

如何让聚合函数在日期上匹配?

【问题讨论】:

  • 你不需要 $elemMatch 这里 - 你可以删除它,看看这是否会改变正在发生的事情? $elemMatch 用于比较数组元素的两个不同属性时,这里是测试单个值。

标签: ruby-on-rails ruby mongodb aggregation-framework moped


【解决方案1】:

以下测试使用聚合框架来近似查询的逻辑等效项。

首先 $unwind 数组,$match,然后 $group 使用 $addToSet 以防有多个匹配的数组元素。请注意,这是一个有损过程,但如果您只需要计数或 id,这是可以接受的。

希望这会有所帮助。

test/unit/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

【讨论】:

    【解决方案2】:

    这样的聚合匹配的正确类型:

    {:$match=>{ :created_at=>{:$gte=>2017-03-07 00:36:30 +0700}}}
    

    这意味着你应该使用方法:

    match_na = {
      '$match': {created_at: { '$gte': (Time.now-30.days) } }
    }
    

    请注意:不要使用 Time.zone.now(因为输出会是另一种格式)。 我很确定大约 100%。我需要 3 个小时。

    再次:像这样制作日期或时间的格式:

    2017-03-07 00:36:30 +0700
    

    不是这个:

    Mon, 03 Apr 2017 00:34:14 ICT +07:00
    

    或者简单的方法:使用方法 mongoize

    (Date.today - 30.days).mongoize
    

    【讨论】:

      【解决方案3】:

      我找到了this short post,这对我有帮助。这是基本的代码示例 - 相比之下似乎非常简单:

      Stat.collection.aggregate({
        '$match' => {
          '$and' => [
            { 'day' => { '$gte' => from.to_date.mongoize } },
            { 'day' => { '$lte' => to.to_date.mongoize } }
          ]
        },
      })
      

      感谢作者!

      【讨论】:

        【解决方案4】:

        我对 ruby​​ 的了解不多,但如果你能粘贴 mongo shell,我可以提供帮助。

        有一些提示: 1. 你正在使用 elemMatch 所以你应该使用 $unwind 2. 之后你尝试使用 $match

        【讨论】:

          猜你喜欢
          • 2015-05-10
          • 1970-01-01
          • 1970-01-01
          • 2012-08-25
          • 2020-08-07
          • 2017-08-20
          • 1970-01-01
          • 2013-01-11
          • 1970-01-01
          相关资源
          最近更新 更多