mongodb get count of orders in each zip code - ruby-on-rails

Hi we are using rails with mongo and we have a collection called orders which contain a specific zip code for each customer. We want to retrieve a count of how many orders belong to each zip code and what time frame they appear in most.
The docs can have basic information such as :
{"zip" : 60010,
"order_time" : <whatever the time for the order is>
}
Right now i have an aggregation using ruby:
coll_orders.aggregate([{"$group" => {"_id" => "$zip", "numOrders" => {"$sum" => 1}}}, {"$sort" => {"numOrders" => 1}}])
and it results with:
{"_id" : 60010,
"numOrders" : 55
}
My question is how do i add functionality in the aggregation so that i can get additional fields where it shows a breakdown of when the orders usually happen? Essentially a result document like :
{"_id" : 60010,
"numOrders" : 55,
"morning" : 25,
"afternoon" : 10,
"evening" : 20
}
edit: spelling/missed quotes

The best way to approach this would be calculate and store the minutes separately using a $project phase and use that to group by. I have provided a sample query below that'll run in the shell for just calculating the orders placed in the morning. You can extend this for the results you are expecting.
db.foo.aggregate( [
{ $project: {
zip: 1,
order_time: 1,
minutes: { $add: [
{ $multiply: [ { $hour: '$order_time' }, 60 ] },
{ $minute: '$order_time' }
] }
} },
{ $group: {
_id:"$zip",
numOrders:{$sum:1}
morning:{$sum:{$cond:[{$lt:["$minutes",12*60]}, 1, 0]}}}}
] );

You can use the following mongoid queries to fetch the data you need:
Count in each zip code:
Order.where(:zip => zip).count
And for count in a given time slot (you will need to create separate queries for each time slot - morning, afternoon, etc.):
Order.where(:zip => zip, :order_time => {'$gt' => start_time, '$lt' => end_time}).count
You can either keep inserting each unique zipcode in a separate collection to get a list of all zip codes, or if you don't run this task often (and your collection is small), you can get a list of all the unique zip codes in your collection using:
zips = Order.all.map{|o| o.zip}.compact.uniq
and iterate over this array and do the above queries.

Related

Multiple queries in Pie Chart

I'm trying to create a pie chart in asp.net mvc however when I'm trying to fetch the data from sql it displays multiple queries save in database, is their a way to get sum of multiple same queries and load the sum in the pie chart
#(Html.EJS().AccumulationChart("container5")
.Series(sr =>
{
sr.Type(Syncfusion.EJ2.Charts.AccumulationType.Pie)
.XName("Heading")
.YName("Factor_Score")
.Name("Factor_Score")
.Explode(true)
.DataLabel(dl => dl.Visible(true).Name("Factor_Score").Position(Syncfusion.EJ2.Charts.AccumulationLabelPosition.Outside).ConnectorStyle(cs => cs.Type(Syncfusion.EJ2.Charts.ConnectorType.Line).Length("5 %")).Font(ft => ft.Size("14px")))
.Animation(animate => animate.Enable(true))
.Radius("70%")
.StartAngle(0)
.EndAngle(360)
.InnerRadius("0%")
.GroupTo("9")
.GroupMode(Syncfusion.EJ2.Charts.GroupModes.Point)
.DataSource(ViewBag.dataSource1).Add();
})
.EnableSmartLabels(true)
.Tooltip(tp => tp.Enable(true))
.LegendSettings(leg => leg.Visible(true)).Title("Loan Audit Finding Detail Checklist").Render()
Controller:
string a = Heading;
int b = Convert.ToInt32(Factor_Score);
PieChartData_Data_View.Add(new PieChartSourceDataData_View(a, b));
[1
For me to give you a complete example I would have to see the whole controller Action. But I assume you would do something like this in the contoller action.
var whateverYouWant = db.YourTable.ToList();
foreach(var arm in whateverYouWant)
{
var sum = arm.ArmQuestions.Count();
}
You would have to load all the categories you wanted to count. You could also do this with a better query like I had posted but without seeing everything, im doing it blind..

Storing toggle button states in Firebase

I want there to be ~100 toggle buttons with a hardcoded item associated with them (All users will have the same items) - The toggle represents whether the user has the item or not, in my SwiftUI app. I'm using Firebase for the backend and have implemented authentication and a database (realtime but I think I'm going to change to firestore).
How would I optimally store whether these buttons are checked / unchecked for each user that uses the app?
A solution could be to have all 100 items stored under the users id in a database but this leads to ALOT of repeated data. (1000 users would mean that 100,000 item states are being stored for only 100 distinct items). (Not great for scalability)
E.g :
{
"users": {
"1": {
"name": "Donald Biden",
"items" : {
"House" : "False",
"Car" : "True",
.
.
},
},
"2": {
"name": "Joe Trump",
"items" : {
"House" : "True",
"Car" : "True",
},
"3": { ... }
}
}
Your solution is also the first approach I would think of.
To improve it: Since a toggle button has only two states, you could only store all true values OR all false ones, whatever you think would lead to less entries.
Example if you store only true: in your app you could check if there's a true value for a specific button for the user, otherwise just set it to false.
Edit: to make it more clear, you would not store "House" : "False" in my example. Because there's no House value then you would just set the button to false.
It really depends how you structured your database. However, if you structure it this way, that might help you to use less data storage:
A table matching returning all keys with their unique ids:
KeysTable:
1: "House",
2: "Car",
...
Then, each user's item list could look like this:
"Items": [1, 4, 5, 6, 8, ...] // List only the key ids with "true" values
Lastly, each user can use the keys table to retrieve which keys are on and which ones are off:
Pseudocode:
OnItems = user.items.map { KeysTable.getValueWithKey[$0] }
OffItems = KeysTable.keys.difference(user.items).map { KeysTable.getValueWithKey[$0] }

Mongoid Return Specific Object from Array in Document

This seems as though it should be simple but I have been struggling with this for a while with no luck.
Let's assume I have a simple document that looks like the following:
{
data: [
{
name: "Minnesota",
},
{
name: "Mississippi",
},
...
]
}
If I run the following query in my Mongo Shell, everything works as I would expect:
db.collection.find({}, {data: {$elemMatch: {name: "Michigan"}}})
Returns:
{ "_id" : ObjectId("5e9ba60998d1ff88be83fffe"), "data" : [ { "name" : "Michigan" } ] }
However, using mongoid, attempting to run a similar query returns every object inside of the data array. Here is one of the may queries I've tried:
Model.where({data: {"$elemMatch": {name: "Michigan"}}}).first
As I mentioned above, that little query returns everything inside the data array, not the specific object I'm trying to pull out of the document.
Any help would be appreciated. I'm trying to avoid returning the results and post-processing them with Ruby. I'd love to handle this at the DB level.
Thank you.
There was a very similar question earlier for a different driver. Apparently the ruby driver behaves differently than the shell.
Try running your find as the equivalent database command:
session.command({'find' => 'my_collection', 'filter' => {}, projection => {data: {$elemMatch: {name: "Michigan"}}}})
Mongoid syntax for projections is only.

DynamoDB contains value in an array using rails

I'm studying DynamoDB using rails and I got a doubt.
I not be able to find a solution on web, so If you can solve it I'll thank.
The doubt is how can I find values into array saved on a table, for example:
I have a lot of data in my_table where there are fields called "numbers" that are arrays like:
[1,2,3,4]
[3,4,5,6]
[1,3,4,7]
[4,7,8,10]
[8,9,12,14]
[12,14,16,20]
So, I want select all entries that contains numbers 1,3,4. In this case four results.
So, my code is
result = dynamodb.scan({
table_name: "my_table",
select: "ALL_ATTRIBUTES",
attributes_to_get: ["numbers"],
scan_filter: {
"numbers" => {
attribute_value_list: [1,3,4],
comparison_operator: "CONTAINS"
}
}
})
But I get this error: One or more parameter values were invalid: Invalid number of argument(s) for the CONTAINS ComparisonOperator
How can I do this action using dynamo DB?
Thanks a lot
Try this and let me know if it works, I know from experience that DynamoDB is very painful to filter.
result = dynamodb.scan(
table_name: 'my_table',
expression_attribute_values: {
':one' => 1,
':two' => 2,
':three' => 3,
':four' => 4
},
filter_expression: 'contains(numbers, :one) OR contains(numbers, :two) OR contains(numbers, :three) OR contains(numbers, :four)'
)
I can't think of anything simpler currently, the method you linked is marked as deprecated, instead you should use expression_attribute_values and filter_expression.

Find and modify, fetch the data, process it and save- Mongoid

I am using Mongoid in my Rails application and found i can use find_and_modify command to update a document as soon as find operation succeeds.
consider a collection User below document structure
name
points
so the documents are saved like
{ "_id" : "51a7420eb09de918204883c4", "name" : "balan", "points" : 1727 }
now how do i update the points count as soon as i fetch the record, is there any way to do like below
User.where(id: "51a7420eb09de918204883c4").find_and_modify( "$set" => { points: points + 1 } )
i.e., the system should fetch the stored points and increment it by 1 and save it back again.
Please suggest.
Thanks for the link James.
Got the solution
User.where(id: "51a7420eb09de918204883c4").find_and_modify({ "$inc" => { points: 1 } })
as per mongoid.org/en/mongoid/docs/querying.html – James Wahlin in comments.
As James said, increment is the way to go:
User.where(id: "51a7420eb09de918204883c4").inc(:points, 100)
This will find all records with the given ID (or whatever you query), increment the value of points by 100, and save it again. Pretty nifty. You can call it on any mongoid query or individual record too, so User.find("some-id").inc(:points, 100) and User.first.inc(:points, 100) will work as well.

Resources