How to Group and Merge key with array in Ruby on Rails - ruby-on-rails

I have list of json value that I need to group according to loc (Location) which has elements of date.
{
"2":[
{
"loc":2,
"date":{
"2020-08-09":"2790.0"
}
},
{
"loc":2,
"date":{
"2020-08-10":"402.0"
}
},
{
"loc":2,
"date":{
"2020-08-11":"522.0"
}
}
],
"12":[
{
"loc":12,
"date":{
"2020-08-10":"765.0"
}
}
],
"13":[
{
"loc":13,
"date":{
"2020-08-11":"135.0"
}
}
]
}
My rails code that I use map and create new object format
result = #weekly_sales_chart.map{ |k|
{
loc: k['location_id'],
date: { k['date']=>k['total']} ,
}
}
respond_with result.group_by { |h| h[:loc]}.map{|f, d| d.inject(:merge)}
Output: (It only group date only one)
[
{
"loc":2,
"date":{
"2020-08-11":"522.0"
}
},
{
"loc":12,
"date":{
"2020-08-10":"765.0"
}
},
{
"loc":13,
"date":{
"2020-08-11":"135.0"
}
}
]
Desired Result: Loc is Group with the same loc value and merge all date under this loc object
[
{
"loc":2,
"date":{
"2020-08-09":"2790.0",
"2020-08-10":"402.0",
"2020-08-11":"522.0"
}
},
{
"loc":12,
"date":{
"2020-08-10":"765.0"
}
},
{
"loc":13,
"date":{
"2020-08-11":"135.0"
}
}
]
Hope someone can help me. Thanks

#Sebastian Palma I already resolved my issue. I refactor your sample code that helps me to produce my desired result:
result = #weekly_sales_chart.map{ |k|
{
loc: k['location_id'],
date: { k['date']=>k['total']} ,
}
}
data = result.group_by { |h| h[:loc]}
respond_with data.map{|_, location_id | location_id.reduce({}) { |result, loc_id|
result.merge(loc_id) do |key, oldval, newval|
key == :date ? oldval.merge(newval) : oldval
end
} }
Thanks for helping out

Related

How to find ids on array who is created facet operator

I have Customer collection on MongoDB. With status field. Which can have the same Id fields.
And I need find first changed value like 'Guest' and push it Id's to specific pipeline named as 'guests'.
And customers with status 'Member' I need push tu another pipeline named as 'members' who Id'd equal Id's from aggregation pipeline 'guests'.
This is done in order to obtain the quantity elements in 'guests' and 'members'.
Its member item:
{"_id"=>{"$oid"=>"5ce2ecb3ad71852e7fa9e73f"},
"status"=>"member",
"duration"=>nil,
"is_deleted"=>false,
"customer_id"=>"17601",
"customer_journal_item_id"=>"62769",
"customer_ids"=>"17601",
"customer_journal_item_ids"=>"62769",
"self_customer_status_id"=>"21078",
"self_customer_status_created_at"=>"2017-02-01T00:00:00.000Z",
"self_customer_status_updated_at"=>"2017-02-01T00:00:00.000Z",
"updated_at"=>"2019-05-20T18:06:43.655Z",
"created_at"=>"2019-05-20T18:06:43.655Z"}}
My aggregation
{
'$sort': {'self_customer_status_created_at': 1}
},
{'$match':
{
'self_customer_status_created_at':
{
"$gte": Time.parse('2017-01-17').beginning_of_month,
"$lte": Time.parse('2017-01-17').end_of_month
}
}
},
{
"$facet": {
"guests":
[
{
"$group": {
"_id": "$_id",
"data": {
'$first': '$$ROOT'
}
}
},
{
"$match": {
"data.status": "guest"
}
}, {
"$group": {
"_id":nil,
"array":{
"$push": "$data.self_customer_status_id"
}
}
},
{
"$project":{
"array": 1,
"_id":0
}
}
], "members":
[
{
"$group": {
"_id": "$_id", "data": {
'$last': '$$ROOT'
}
}
},
{
"$match": {
"data.status": "member",
"data.self_customer_status_id": {
"$in": [
"$guests.array"
]
}
}
}
}
]
}
}, {
"$project":
{
"members": 1,
"guests.array": 1
}
}
]
).as_json
Instead "guests.array" array? I have error:
Mongo::Error::OperationFailure: $in needs an array (2)
What am I doing wrong?
Sorry my English!
second expression in faced doesnt seen first expression
need delete
,
"data.self_customer_status_id": {
"$in": {
"$arrayElemAt":
[
"$guests.array",
0
]
}
}
{"$match": {"data.self_customer_status_id": { "$in": ["guests.array"] } } }
```
this link paste before $project

how to get the union of hashes in ruby for this json structure

Below is json I translated from ruby hash for ease of representation for this question using hash.to_json. Notice how the key range is being repeated since the values in the nested doc are different. How do I merge the ranges so that for the weight key both "gt": 2232, "lt": 4444 fall under the one hash key weight inside range. Is there some union or collapse method in ruby to sort of "compactify" hashes?
{
"must": [
{
"match": {
"status_type": "good"
}
},
{
"range": {
"created_date": {
"lte": 43252
}
}
},
{
"range": {
"created_date": {
"gt": "42323"
}
}
},
{
"range": {
"created_date": {
"gte": 523432
}
}
},
{
"range": {
"weight": {
"gt": 2232
}
}
},
{
"range": {
"weight": {
"lt": 4444
}
}
}
],
"should": [
{
"match": {
"product_age": "old"
}
}
]
}
Want to change the above to this:
{
"must": [
{
"range": {
"created_date": {
"gte": 523432,
"gt": "42323"
}
}
},
{
"range": {
"weight": {
"gt": 2232,
"lt": 4444
}
}
}
],
"should": [
{
"match": {
"product_age": "old"
}
}
]
}
I don't know of a built in way to handle something like this, but you could write a method that does something like this:
def collapse(array, key)
# Get only the hashes with :range
to_collapse = array.select { |elem| elem.has_key? key }
uncollapsed = array - to_collapse
# Get the hashes that :range points to
to_collapse = to_collapse.map { |elem| elem.values }.flatten
collapsed = {}
# Iterate through each range hash and their subsequent subhashes.
# Collapse the values into the collapsed hash as necessary
to_collapse.each do |elem|
elem.each do |k, v|
collapsed[k] = {} unless collapsed.has_key? k
v.each do |inner_key, inner_val|
collapsed[k][inner_key] = inner_val
end
end
end
[uncollapsed, collapsed].flatten
end
hash[:must] = collapse hash[:must], :range
Note that this is a specific solution that's mainly applicable to the presented problem. It only works for the hash/array depths specified here. You could probably write a recursive solution that could potentially work at any level of depth with a bit more work.

Ruby use find to loop through an array and return the matching value

I am trying to loop through an array using find to find and return a specific id.
This is my structure:
{
"employees": [
{
"emp_id": "1",
"tutorials": [
{
"id": "test1"
},
{
"id": "test2"
},
{
"id": "test3"
},
{
"id": "test4"
},
{
"id": "test5"
}
]
}
]
}
So basically I am trying to see if the above structure contains a tutorial id of 'test3' and return it.(i.e return 'test3' in this case)
I can get the desired result using a combination of map and find like this:
my_tutorial = employees.map { |employee|
employee.tutorials.find { |tutorial|
tutorial.id == 'test3'
}
}.first
my_tutorial
But I want to know if there is a better way using find . I tried the following but it returns the ruby object instead of the id.
employees.find { |employee|
employee.tutorials.find { |tutorial|
tutorial.id == 'test3'
}
}
Here is what i did to make it work using find. Not sure if it is any better:
my_id = employees.find { |employee|
employee.tutorials.find { |tutorial|
tutorial.id == 'test3'
}
}
my_id.tutorials.first.id
If you have to get only the first record do as follows:
employees[0].tutorials.detect {|r| r.id == 'test3' }

Tire multi search with RAW Json

I'd like make a multi query on Elasticsearch through Tire but with raw JSON
I can to a single request like this
#search = Tire.search('questions', query: {
function_score: {
query: {
bool: {
must: [
{
terms: {
interests: [2943,5106,3540,1443,3639]
}
}
]
}
},
random_score: {}
}
})
But for multiple I can't.
I'd like somthing like this, but it's not correct for now...
#search = Tire.multi_search 'questions' do
search :level2 do
query: {
function_score: {
query: {
bool: {
must: [{
terms: {
interests: [5090,2938,3062]
}}]
}
},
random_score: {}
}
}
end
end
Do you now how I could do to make it work?
Thank you
I found the solution.
Actually, in my case Search method is requiring :payload key in options params
#search = Tire.multi_search 'questions' do
search( :level1, :payload => {
query: {
function_score: {
query: {
bool: {
must: [
{
terms: {
interests: [2943,5106,3540,1443,3639]
}
},{
term: {
difficulty: 1
}
}
]
}
},
random_score: {}
}
}})
search( :level2, :payload => {
query: {
function_score: {
query: {
bool: {
must: [
{
terms: {
interests: [5160,2938,3062]
}
},{
term: {
difficulty: 2
}
}
]
}
},
random_score: {}
}
}})
end

ElasticSearch returns items that are too far away when using a geo_distance filter

When I am searching my ElasticSearch documents using a nested filter -> and -> geo_distance I retrieve documents which are too far away (and I don't want returned.) You can see the query and a screenshot below of the results (raw results on the left and manually filtered results on the right).
Here's another copy of the query:
{
"query":{
"match_all":{
}
},
"filter":{
"and":[
{
"term":{
"PropertySubType":"Single Family"
}
},
{
"term":{
"City":"Los Angeles"
}
},
{
"geo_distance":{
"distance":"2.25miles",
"Location":[
34.111583657,
-118.324646099
]
}
},
{
"range":{
"BedroomsTotal":{
"gte":3
}
}
},
{
"range":{
"BuildingSize":{
"gte":3000
}
}
},
{
"range":{
"YearBuilt":{
"lte":2000
}
}
},
{
"terms":{
"ListingStatus":[
"Active",
"Pending",
"Closed"
]
}
}
]
},
"size":100
}
Adding the option "distance_type" and setting it to "plane" fixed this issue. See "distance_type" here:
http://www.elasticsearch.org/guide/reference/query-dsl/geo-distance-filter.html

Resources