I am not sure that this is a valid question or not. I have started working on mongodb aggregation. I have to make a graph for the data on daily, weekly, monthly basis.
I am using "$dayOfMonth", "$week", "$month" to group by depending on the date provided. ex if from and to dates difference is less or equal to 6 I am grouping on daily basis using "$dayOfMonth",
If from and to dates difference is greater than 6 and less than 30 grouping is done of "$week" and if differece is greater than 30 then grouping is done on monthly basis "$month".
I am passing date in my "$match". Is it possible to push 0 as keys if the gouping is not present.
example - from_date = "01/01/2018" to_date = "30/6/2018"
so grouping will be done on month. and suppose if I dont have date for 3 and 4th & 5th month. I want to push 0 in the nested keys as the value.
output = [
{"_id": "01/01/2018", "counter":12},
{"_id": "01/02/2018", "counter": 15},
{"_id":"01/06/2018", counter: 10}
]
expected_output =
[
{"_id": "01/01/2018", "counter":12},
{"_id": "01/02/2018", "counter": 15},
{"_id":"01/03/2018", counter: 0},
{"_id":"01/04/2018", counter:0},
{"_id":"01/05/2018", counter: 0},
{"_id":"01/06/2018", counter: 10}
]
I am using Rails and Mongoid Gem.
Query That I am using
converted = Analytics::Conversion::PharmacyPrescription.collection.aggregate([
{ "$match" => {
"organisation_id" => org_id.to_s,
"date" => {
"$gte" => from_date,
"$lte" => to_date
},
"role_ids" => {"$in" => [role_id, "$role_ids"]}
}
},{
"$project" => {
"total_count" => 1,
"converted_count" => 1,
"not_converted_count" => 1,
"total_invoice_amount" => 1,
"user_id" => 1,
"facility_id" => 1,
"organisation_id" => 1,
"date" => 1,
}
},{
"$group" => {
"_id" => { "#{groupby}" => "$date" },
"total_count" => {"$sum" => "$total_count"},
"converted_count" => { "$sum" => "$converted_count" },
"not_converted_count" => { "$sum" => "$not_converted_count"},
}
}
]).to_a
The Aggregation Framework can only aggregate the documents you have. You are actually asking it to add groups for documents that do not exist, but it has no way to "know" which groups to add.
What I would do is run the query as you have it, and afterwards "spread" the date units according to the chosen granularity (in your example it will be 01/01/2018, 01/02/2018, 01/03/2018, 01/04/2018, 01/05/2018, 01/06/2018, and run a simple function which will add an entry for each missing unit.
Related
I am building an Rails 5 app.
In this app I create a user with customfields. The output I get from the client (Javascript) is a bit wrong (and I have no idea how to change that). How can I "transform" the output I get into the output I must have?
The below is what I get
"user_customfields_attributes" => {
"1533038627616" => {
"customfield_id" => "1", "value" => "test 1"
}, "1533038627617" => {
"customfield_id" => "2", "value" => "test 2"
}
}
The below is what I need
"user_customfields_attributes" => [{
"customfield_id" => 1,
"value" => "test 1"
}, {
"customfield_id" => 2,
"value" => "test 2"
}]
Thankful for all help!
I have a User table with "created" date field. Now I want to know how many new users were created on each day last week, as well as the total users by the end of each day (since the beginning of time).
For example:
{
{
day: 27,
new_users: 5,
total_users: 100
}, {
day: 28,
new_users: 7,
total_users: 107
}, {
day: 29,
new_users: 2,
total_users: 109
}
}
I already got the new_users part by using simple grouping and summing. Code below is mongoid/Ruby.
results = User.collection.aggregate(
[{
"$match" => {
created: { "$gte" => 1.week.ago.beginning_of_day, "$lte" => Time.now }
}
},
{
"$group" => {
_id: {
year_joined: { "$year" => "$created" },
month_joined: { "$month" => "$created" },
day_joined: { "$dayOfMonth" => "$created" }
},
count: { "$sum" => 1 }
}
},
{
"$sort" => {"_id.year_joined" => 1, "_id.month_joined" => 1, "_id.day_joined" => 1}
}]
)
How do I also get the total_users in the results?
You're getting close with your attempt. One thing is that since you're starting out by filtering down to own the last week, you don't need to care about the year or month.
Note: I don't know ruby, so I wrote it as I would in the mongo shell.
{
"$match" => {
created: { "$gte" => 1.week.ago.beginning_of_day, "$lte" => Time.now }
}
},
{
$group: {
_id: {"$dayOfMonth": "$created" },
day: {"$dayOfMonth": "$created" },
newUsers: { "$sum": 1}
}
},
{
"$sort" => {"_id.year_joined" => 1, "_id.month_joined" => 1, "_id.day_joined" => 1}
}
That will get you the day and newUsers, but it wont get you the total. I don't actually that is possible in a single query. One alternative might be to give each user a unique number and just take the max of the numbers for that day.
I want to fetch total records for my product group by product title and order by product title. I am using monogomapper in ror.
I tried :
tetsing code
#test_product_details_array_full=Product.collection.aggregate([
{"$match" => {:store_id => #store_id, :product_active=> "yes"}},
{"$project"=> {"product_name"=> 1, "output"=> { "$toLower"=> "$product_name" }}},
{"$sort"=> { "output"=>1 } },
{"$project"=> {product_name: 1, _id:0}},
{"$group" => {_id: "$product_name", Product: { "$push"=> "$$ROOT"}}},
]);
testing code
I am getting blank array in out put. So how do I get proper result.
I have the following table code:
member_id_and_first_name_and_nps_score_and_comments = [["14169021-00",
"Chris", 9, "YMCA in the Tampa, FL area is fantastic. I would like to
see the level of support for other sports also provided to
racquetball."], ["1660592-00", "Nayrone", 9, "There are so many
offerings for activities and there are many convenient locations
throughout the area."], ["16183029-00", "Mary", 9, "I like the staff
but the showers are gross"], ["16257833-00", "Phyllis", 10, "A
comfortable environment, a place where you can meet people and most
importantly the staff is always available."], ["1629846-00", "Joan",
10, "Cost, Distance , Family Friendly"], ["16204559-00", "Lisa-Marie",
5, "The facilities are fairly crowded which makes working out on
equipment or participating in classes cramped and difficult. "],
["16258576-00", "Michael", 7, "yhe cost way to much\r\n"],
["16161644-00", "April", 10, ""], ["1663157-00", "Mariela", 10, "Great
customer service, clean facilities and professional staff "],
["16114120-00", "Alison", 10, "The Y offers great programs and is
active in the local community. "], ["16177159-00", "Sheri", 10, "The Y
is a place for everything. It is a place for fitness, fellowship,
socialization, community, upward progretion of the youth, employment
opps..."]]
table([
["Member ID", "First Name", "NPS Score", "Comments"],
[member_id_and_first_name_and_nps_score_and_comments]
.transpose.reject{ |x| x[2].nil? }
],
:position => :center, :column_widths => {0 => 50, 1 => 60, 2 => 45, 3 => 285}) do
row(0).style :background_color => 'C0C0C0'
end
The table is generating with only the header row (Member ID, First Name, etc.). The actual member_id_and_first_name_and_nps_score_and_comments array is not populating in the column.
Any thoughts as to why this is?
Try:
table([
["Member ID", "First Name", "NPS Score", "Comments"],
*member_id_and_first_name_and_nps_score_and_comments.reject{ |x| x[2].nil? }
],
:position => :center, :column_widths => {0 => 50, 1 => 60, 2 => 45, 3 => 285}) do
row(0).style :background_color => 'C0C0C0'
end
I have an Element model that belongs to User. I am trying to calculate the following hash: how many users have element count of 1, 2, 3, etc. The approach I take is to first generate a hash of {user -> num elements}, then I sort-of invert it using a second map-reduce.
Here's what I have so far:
Element.map_reduce(%Q{
emit(this.user_id, 1);
}, %Q{
function(key, values) {
return Array.sum(values);
}
}).out(inline: true).map_reduce(%Q{
if (this.value > 1) {
emit(this.value, this._id);
}
}, %Q{
function(element_count, user_ids) {
return user_ids.length;
}
}).out(inline: true)
This gives me an "undefined method `map_reduce'" error. I couldn't find the answer in the docs. Any help would be great.
I calculated the hash using aggregate instead mapreduce, first grouping by user, and then grouping again by elements count:
Element.collection.aggregate([
{
"$group" => {
"_id" => "$user_id", "elements_count" => {"$sum" => 1}
}
},
{
"$group" => {
"_id" => "$elements_count", "users_count" => {"$sum" => 1}
}
},
{ "$project" => {
"_id" => 0,
"users_count" => '$users',
"elements_count" => '$_id',
}
}
])
This returns the following array:
[
{"users_count"=>3, "elements_count"=>2},
{"users_count"=>4, "elements_count"=>3},
...
]
If needed it can also be sorted using $sort operator