Having different count per key in jsonb - ruby-on-rails

I have values in a table called Translation, that contains for every values per example:
=> {"fr"=>"Jaune", "de"=>"", "en"=>"", "bg"=>"", "hr"=>"", "es"=>"", "hu"=>"", "it"=>"", "lt"=>"", "lv"=>"", "nl"=>"", "pl"=>"", "pt"=>"", "ro"=>"", "cs"=>""}
and I'm looking to get the the number of the translation for each language:
I'm trying :
Translation.where("values->>'fr' IS NOT NULL").count
but it giving me 0, which is not correct, do anyone knows how to do it correctly?

The problem that you have is that the keys that don't have values, still exist in the json, so "is not null" will return all of them because the key exist. you have two options here, you can remove the empty keys from the database, so not null will work, or, change it to see if the key is empty
You can do it like this
Translation.where("values->>'fr' <> ''").count
and it will work with the structure that you have right now.

Related

Finding missing records from db

I am trying to validate my configuration. So I have a piece of code like :
ConfigurationAttribute.where(key: [
'a', 'b', 'c'
])
If someone forgets to set key a, on the configuration or b, I want to be able to find the missing ones. Now I realize the record doesn't actually exists in the db, so there is nothing to find and instantiate the ConfigurationAttribute record from.
How would you solve a problem like this?
I can check if the count of attributes is equal to 3, that will make sure if all keys are set or not. But then again if I was troubleshooting this error, I would be frustrated because I don't know which one is missing and I would have to go and look one by one who is missing.
You could pluck the keys from that query, and compare it to the expected set:
required_keys = ['a', 'b', 'c']
actual_keys = ConfigurationAttribute.where(key: required_keys).pluck(:key)
if actual_keys != required_keys
# This could be a model validation, or whatever. But for example:
raise "Whoops! You configuration contains the keys: #{actual_keys}. Should contain: #{required_keys}"
end
The exact implementation details may vary slightly -- for example, maybe there can be multiple ConfigurationAttributes for the same key? Maybe there cannot be any ConfigurationAttributes for different keys? Maybe the required_keys varies depending on some condition (in which case, that could be a method call rather than a variable)? ...
... In which case, you may wish to modify that query, or the if statement, or add an additional validation, or whatever.

stored procedure returning 2 result set mybatis 3

I am facing a problem in mybatis 3. I have a stored procedure that returns two result sets(resultset of object1, result set of object2).
I have created a resultMap for each result set
result map for object1(Create a class pojo Object1)
result map for object2(Create a class pojo Object2)
which give as something like this:
<resultMap id="object1" type="Object1" />
<resultMap id="object2" type="Object2" />
and for the call of the stored proc I have this:
<select id="pscall" parameterType="Integer"
resultMap="object1,object2" statementType="CALLABLE">
{ CALL PS(
#{id, mode=IN},
) }
</select>
Now when executing all this, I got effectively two lists with the number wanted of object1 and object2, but these two lists are filled with null objects, like the first list I got 3 elements and they are all null and the second 20 elements all null.
I know it's something wrong I made with the mapping, but at this point, I cannot see where the problem is.
You're asking us to deduce quite a lot, but I think it is clear that the basic mechanism of multiple result set handling is working correctly (you are getting the correct number of objects). What's not working is mapping rows to objects. That can only be happening if Object1 and Object2 do not have any attributes that match the columns coming back from the SP.
For example, if the first result set contains "ID, DESCRIPTION", then Object1 must have "id" and "description" properties (it is case insensitive).
If you don't know what will be coming back from the SP, then change the type of each <resultMap> to map. Then MyBatis will build lists of maps and you can look in the map to see the values that came back from the SP and their column names.

merge json and remove duplicates ruby rails

I have the following json
Suppose my selection in mobile then this fields will be generated
{"Style":"convertible","Year":"2010","Color":"green"}
{"Style":"convertible","Year":"2010","Color":"red"}
And if my selection is bike then this field will be generatd
{"model":"2012","mileage":"20kmph","Color":"red"}
How do i achieve the above result.
Edit-1
I have the form in which some of the fields with be auto generated based on category selection. I have converted the auto generated fields to json and stored in database as single column.
Image url
I don't know how to explain can you understand what I am looking for. Check out my screenshots for better understanding
I'm assuming (for some crazy reason) that you will be using Ruby to do this.
But first, your expected output is wrong because you can't have a hash with duplicate keys:
{"Color": "green", "Color": "red"}
...is impossible. Same goes for the "Year" keys. Think of keys within a hash as Highlanders. THERE CAN ONLY BE ONE (of the same name). Therefore, your actual expected output would be:
{"Style":"convertible", "Year":"2012", "Color":"red", "name":"test"}
Or whatever. Anyway...
Step 1: Convert JSON to a Ruby Hash
require 'json'
converted = JSON.parse '[{"Style":"convertible","Year":"2010","Color":"green"},
{"Style":"convertible","Year":"2010","Color":"red"},
{"name":"test","Year":"2012","Color":"red"}]'
Step 2: Merge them
merged = {}
converted.each { |c| merged.merge! c }
Now the merged variable should look like the above actual expected output.
The only problem left is deciding which duplicate keys override which other duplicate keys. What matters here is the order in which you merge the hashes. The ones merged last overrides any existing duplicate key/values. Hope that helps.

How to manipulate hash keys to transform numeric months to names

I have an AR query that returns a hash of events per month, ordered by month
o.events.group("to_char(date,'MM')").order("to_char(date,'MM')").size()
I'm using numeric months in this query as it was the best way I could find to get things in the correct order, and I also need to do some other manipulations on the hash.
Before display the results, I need to convert the numeric months back to words. I added the following to the end of the query
.each_key{ |key| Date::MONTHNAMES[key] }
But i get
TypeError: can't convert String into Integer.
So i tried
.each_key{ |key| Date::MONTHNAMES[key.to_i] }
But the months remain in numeric form
{"01"=>4, "02"=>3.....
How can i manipulate this hash to get
{"January"=>4, "February"=>3.....
Make a new Hash. If you can't, make a new key in the current hash and delete the original key. You can't simply change a key, since key is a local variable in the block, and changing it in no way impacts the contents of the Hash.
This ? :
def number_to_month(number)
(Time.now.beginning_of_year + number.months).strftime("%B")
end
There are ways to generate a new hash but I think you could just convert the strings to month names in your view right before displaying them. Use the code you already wrote inside the block in your question but put it in your view.

Ruby on Rails+PostgreSQL: usage of custom sequences

Say I have a model called Transaction which has a :transaction_code attribute.
I want that attribute to be automatically filled with a sequence number which may differ from id (e.g. Transaction with id=1 could have transaction_code=1000).
I have tried to create a sequence on postgres and then making the default value for the transaction_code column the nextval of that sequence.
The thing is, if I do not assign any value to #transaction.transaction_code on RoR, when I issue a #transaction.save on RoR, it tries to do the following SQL:
INSERT INTO transactions (transaction_code) VALUES (NULL);
What this does is create a new row on the Transactions table, with transaction_code as NULL, instead of calculating the nextval of the sequence and inserting it on the corresponding column. Thus, as I found out, if you specify NULL to postgres, it assumes you really want to insert NULL into that column, regardless of it having a default value (I'm coming from ORACLE which has a different behavior).
I'm open to any solution on this, either if it is done on the database or on RoR:
either there is a way to exclude attributes from ActiveRecord's
save
or there is a way to change a column's value before insert with a trigger
or there is a way to generate these sequence numbers within RoR
or any other way, as long as it works :-)
Thanks in advance.
For the moment, you might be stuck fetching and assigning the sequence in your ROR model like this:
before_create :set_transaction_code_sequence
def set_transaction_code_sequence
self.transaction_code = self.class.connection.select_value("SELECT nextval('transaction_code_seq')")
end
I'm not particularily fond of this solution, since I'd like to see this corrected in AR directly... but it does do the trick.
If you want to insert the default value in to a column in an INSERT statement, you can use the keyword DEFAULT - no quotes:
INSERT INTO mytable (col1, col2) VALUES (105, DEFAULT);
Or you could spell out the default, nextval(...) in your case. See the manual here.
A trigger for that case is simple. That's actually what I would recommend if you want to make sure that only numbers from your sequence are entered, no matter what.
CREATE OR REPLACE FUNCTION trg_myseq()
RETURNS trigger AS
$BODY$
BEGIN
NEW.mycol := nextval('my_seq');
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
CREATE TRIGGER myseq
BEFORE INSERT
ON mytable
FOR EACH ROW
EXECUTE PROCEDURE trg_myseq();
On a side note:
If you want to assign your own (non-sequential) numbers as 'sequence', I have written a solution for that in an answer a couple of days ago:
How to specify list of values for a postgresql sequence
I was still experiencing this issue with Rails7 - I could see that Rails was generating a NULL in the insert, but changing the column from integer to bigint solved it. - Rails then does not supply a value for my sequenced column and the DEFAULT nextval('number_seq') is used.

Resources