I'm trying to make a query grouping by date with different formats (day, month, year), I know that it's a easy query on typically SQL databases.
You can see the code on this link: https://gist.github.com/jrdi/b3f824fa4e7531c43bfd
Know I can run:
> Patient.group_by('created_at', 'day')
=> [{"_id":"11/10/2013","value":{"count":3.0}}]
In my opinion is really weird all this code for make a simple group by. Am I missing something important?
PD: I know that method self.map
and some interpolation are not the best way but know I care about Mongo stuff.
Simply add it: {$project : { month : {$month : "$entryTime"}, year : {$year : "$entryTime"}, expenseAmount : 1 }}, Note that if field does not exist in document, then $sum returns 0.
The best format to store date and time in MongoDB is native javascript Date() or ISO date format as it internally converts it into BSON native Date object.
Here's an answer that uses the aggregation framework to group by date. I hope that you like it.
app/model/patient.rb
class Patient
include Mongoid::Document
field :name, type: String
def self.group_by(field, format = 'day')
key_op = [['year', '$year'], ['month', '$month'], ['day', '$dayOfMonth']]
key_op = key_op.take(1 + key_op.find_index { |key, op| format == key })
project_date_fields = Hash[*key_op.collect { |key, op| [key, {op => "$#{field}"}] }.flatten]
group_id_fields = Hash[*key_op.collect { |key, op| [key, "$#{key}"] }.flatten]
pipeline = [
{"$project" => {"name" => 1, field => 1}.merge(project_date_fields)},
{"$group" => {"_id" => group_id_fields, "count" => {"$sum" => 1}}},
{"$sort" => {"count" => -1}}
]
collection.aggregate(pipeline)
end
end
test/unit/patient_test.rb
require 'test_helper'
require 'pp'
class PatientTest < ActiveSupport::TestCase
def setup
Patient.delete_all
end
test "group by date" do
[
{"name" => "John", "created_at" => Date.new(2012, 10, 10).mongoize},
{"name" => "Jane", "created_at" => Date.new(2012, 10, 31).mongoize},
{"name" => "Mary", "created_at" => Date.new(2012, 10, 31).mongoize},
{"name" => "Mark", "created_at" => Date.new(2012, 12, 12).mongoize},
{"name" => "Alex", "created_at" => Date.new(2013, 11, 10).mongoize},
{"name" => "Andy", "created_at" => Date.new(2013, 10, 31).mongoize},
{"name" => "Toni", "created_at" => Date.new(2013, 10, 31).mongoize},
{"name" => "Cori", "created_at" => Date.new(2013, 11, 10).mongoize}
].each do |patient|
Patient.create(patient)
end
puts "\nMongoid::VERSION:#{Mongoid::VERSION}\nMoped::VERSION:#{Moped::VERSION}"
pp Patient.group_by('created_at', 'month')
end
end
$ rake test
Run options:
# Running tests:
[1/1] PatientTest#test_group_by_date
Mongoid::VERSION:3.1.5
Moped::VERSION:1.5.1
[{"_id"=>{"year"=>2012, "month"=>10}, "count"=>3},
{"_id"=>{"year"=>2013, "month"=>10}, "count"=>2},
{"_id"=>{"year"=>2013, "month"=>11}, "count"=>2},
{"_id"=>{"year"=>2012, "month"=>12}, "count"=>1}]
Finished tests in 0.042561s, 23.4957 tests/s, 0.0000 assertions/s.
1 tests, 0 assertions, 0 failures, 0 errors, 0 skips
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With