how do I grab a deeply nested value in ruby? - ruby-on-rails

so I am trying to filter invoices by their sale_id. there is a lot of information on an invoice and I need to grab the sale_id off of a hash inside of an array. I am filtering invoices by this value but have had trouble getting the correct result
I search for invoices from a specific store with invoices = store.invoices. this will return an array populated with hashes. here is apart of what I get for one hash:
rows: [{"name"=>"sale 1", "item_id"=>1289, "sale_id"=>1413, "single_amount"=>"5000.0", "amount"=>"5000.0", "quantity"=>1, "charges_amount"=>"0.0", "tax_amount"=>"0.0", "tax_rate_id"=>nil, "total_amount"=>"5000.0"}],
note: nil,
total: 0.5e4,
paid_total: 0.0,
i've tried: filtered = invoices.select { |i| i['sale_id'] == sale.id } but this just returns an empty array. I thought maybe I just needed to reach a level deeper so I tried invoices.select{|i| i['rows'][sale_id] == 1413} but I again get an empty result.
I also tried rows = invoices.map(&:rows), which will give me a nested array with hashes of rows from all the different invoices. but this doesn't help me much because I will ultimately need the individual invoice id after finding ones that are a match. I've been stuck on this for so long and feel like I'm missing a basic piece here and would love some insight. thanks!
Edit: I was able to get this to work by modifying a suggestion with: invoices.select { |i| i['rows'][0]['sale_id'] == self.id }

You need to get the first item in the rows array and then select sale_id
invoices.select { |i| i['rows'][0]['sale_id'] == sale.id }
You can also use dig to prevent error in case some key/values are missing.
invoices.select { |i| i.dig('rows', 0, 'sale_id') == sale.id }

Related

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.

Ruby on Rails statement executed on an array check if subelement string is unique

I have an array objects, for this example lets call it Diff. These diffs have multiple fields that are not all the same (old_image, new_image, url, etc). new_image and old_image in this case have fields on them, most importantly a field called image_file_name.
I want to get an array of all the diffs with an unique old_image.image_file_name i.e. no diff should have an old_image with the same file name.
I believe the logic should look something like this.
unique_diffs = Array.new
#diff.build.diffs.each { |diff|
if diff.old_image.image_file_name != #diff.old_image.image_file_name
unique_diffs.push(diff)
end
}
Or something like this
#unique_diffs = #diff.build.diffs.map{|diff| diff.old_image.image_file_name}.uniq
Any help would be much appreciated.
Try something like this:
Diff = Struct.new(:old_image)
Image = Struct.new(:image_file_name)
diffs = [
Diff.new(Image.new('name1')),
Diff.new(Image.new('name2')),
Diff.new(nil),
Diff.new(Image.new('name1')),
]
uniqs = diffs.select { |diff| diff.old_image }.uniq { |diff| diff.old_image.image_file_name }
p uniqs # prints Diff with name1 and Diff with name 2
The only important line is the one that calls select and uniq.
You need to use select to leave only the diffs with the old image, and then use uniq to drop those with the duplicated image file names.
I ended up using the loop, I was hoping to make this cleaner with the uniq function but it didn't seem to work, it gave me back all the diffs instead of the ones with the unique old image filename.
#diff.build.diffs.each { |diff|
if diff.old_image.image_file_name == #diff.old_image.image_file_name
# Logic went here
end
}
Still open to improving this but for now this will have to do.

Ruby, accessing a nested value in a hash

I have the following hash. Using ruby, I want to get the value of "runs". I can't figure out how to do it. If I do my_hash['entries'], I can dig down that far. If I take that value and dig down lower, I get this error:
no implicit conversion of String into Integer:
{"id"=>2582, "entries"=>[{"id"=>"7", "runs"=>[{"id"=>2588, ...
Assuming that you want to lookup values by id, Array#detect comes to the rescue:
h = {"id"=>2582, "entries"=>[{"id"=>"7", "runs"=>[{"id"=>2588}]}]}
# ⇓⇓⇓⇓⇓⇓⇓ lookup element with id = 7
h['entries'].detect { |e| e['id'] == 7 }['runs']
.detect { |e| e['id'] == 2588 }
#⇒ { "id" => 2588 }
As you have an array inside the entries so you can access it using an index like this:
my_hash["entries"][0]["runs"]
You need to follow the same for accessing values inside the runs as it is also an array.
Hope this helps.
I'm not sure about your hash, as it's incomplete. So , guessing you have multiple run values like:
hash = {"id"=>2582, "entries"=>[{"id"=>"7", "runs"=>[{"id"=>2588}]},
{"id"=>"8", "runs"=>[{"id"=>2589}]},
{"id"=>"9", "runs"=>[{"id"=>2590}]}]}
Then, you can do
hash["entries"].map{|entry| entry["runs"]}
OUTPUT
[[{"id"=>2588}], [{"id"=>2589}], [{"id"=>2590}]]

Deleting a specific hash inside an array of hashes using a variable

I have an array of hashes like this:
"[{:id=>15, :name=>"Hockey", :num_of_boxes=>2, :total_price=>6.98}, {:id=>14, :name=>"Baseball", :num_of_boxes=>3, :total_price=>8.97}, {:id=>5, :name=>"Basketball", :num_of_boxes=>2, :total_price=>5.98}]"
In my controller I want to delete the hash where the ID is set as a variable elsewhere. How would I go about doing this?
This is what I was trying to get to work, and I think it's the right path? id would be set in the controller before this method runs:
new_array = eval(#garden.seed_cart).reject { |h| id.include? h['15'] }
Thanks for your help!
Try this:
arr.delete_if { |hash| id.include?(hash[:id]) }
Note (comparison to the #reject suggestion): #delete_if returns the unchanged array if there is nothing to delete. #reject returns nil. Also, #delete_if modifies the array in place, whereas #reject (without !) simply returns a changed version of the array but leaves the original unchanged.
edit
Note: the use of include? here assumes that there may be multiple integers that are being filtered out, i.e. if id (or ids) is actually an array. If you just need to filter one ID, you can use a straightforward comparison with hash[:id] == id inside the block. Thanks to smathy for pointing this out in the comments.
If you have this data:
data = [{:id=>15, :name=>"Hockey", :num_of_boxes=>2, :total_price=>6.98}, {:id=>14, :name=>"Baseball", :num_of_boxes=>3, :total_price=>8.97}, {:id=>5, :name=>"Basketball", :num_of_boxes=>2, :total_price=>5.98}]
And you want to remove this ids from data:
ids = [14,15]
You can do
new_array = data.reject { |h| ids.include? h[:id] }
And you get
new_array = [{:id=>5, :name=>"Basketball", :num_of_boxes=>2, :total_price=>5.98}]
Note: data in an array (not a string) and ids is an array too.

Query - Does Not Contain

I have a search query to lookup Customers.
I would like to use the Sounds Like function to return additional possible results, however this is returning some of the same results in my main search query.
I would like to only show the additional results in a partial view.
I basically need a DoesNotContain.
Here is what I have so far for my main query:
customer = customer.Where(c => SqlFunctions.StringConvert((double)c.CustomerID).Trim().Equals(searchString)
|| c.CustomerName.ToUpper().Contains(searchString.ToUpper()));
And for the additional results:
customeradditional = customeradditional.Where(c => SqlFunctions.SoundCode(c.CustomerName.ToUpper()) == SqlFunctions.SoundCode(searchString.ToUpper()));
The only possible solution I can see at the minute is to do a Contains Query, loop through each item and get the IDs, then do another query for CustomerID != 1 or CustomerID != 2 or CustomerID != 3, etc.
Try using Except:
customeradditional = customeradditional
.Where(c => SqlFunctions.SoundCode(c.CustomerName.ToUpper()) == SqlFunctions.SoundCode(searchString.ToUpper()))
.Except(customer);
I am not sure if I understood you correct:
From what you have now, the customeraddtional query does return some of the customers already returned in the customer query. And you only want the results, which are not already contained in the customer query.
Then the solution would be:
customeradditional = customeradditional.Where(c =>
SqlFunctions.SoundCode(c.CustomerName.ToUpper()) ==
SqlFunctions.SoundCode(searchString.ToUpper()))
.Except(customer);
This way your are explicitly excluding every item, which is present in the customer object.

Resources