MySQL increment value in a text field - mysql

Say I have a text field with JSON data like this:
{
"id": {
"name": "value",
"votes": 0
}
}
Is there a way to write a query which would find id and then would increment votes value?
I know i could just retrieve the JSON data update what I need and reinsert updated version, but i wonder is there a way to do this without running two queries?

UPDATE `sometable`
SET `somefield` = JSON_REPLACE(`somefield`, '$.id.votes', JSON_EXTRACT(`somefield` , '$.id.votes')+1)
WHERE ...
Edit
As of MySQL 5.7.8, MySQL supports a native JSON data type that enables efficient access to data in JSON documents.
JSON_EXTRACT will allow you to access a particular JSON element in a JSON field, while JSON_REPLACE will allow you to update it.
To specify the JSON element you wish to access, use a string with the format
'$.[top element].[sub element].[...]'
So in your case, to access id.votes, use the string '$.id.votes'.
The SQL code above demonstrates putting all this together to increment the value of a JSON field by 1.

I think for a task like this you're stuck using a plain old SELECT followed by an UPDATE (after you parse the JSON, increment the value you want, and then serialize the JSON back).
You should wrap these operations in a single transaction, and if you're using InnoDB then you might also consider using SELECT ... FOR UPDATE : http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
This is sort of a tangent, but I thought I'd also mention that this is the type of operation that a NoSQL database like MongoDB is quite good at.

Related

How do I update data inside a stringified JSON object in SQL?

So I have three databases - an Oracle one, SQL Server one, and a Postgres one. I have a table that has two columns: name, and value, both are texts. The value is a stringified JSON object. I need to update the nested value.
This is what I currently have:
name: 'MobilePlatform',
value:
'{
"iosSupported":true,
"androidSupported":false,
}'
I want to add {"enableTwoFactorAuth": false} into it.
In PostgreSQL you should be able to do this:
UPDATE mytable
SET MobilePlatform = jsonb_set(MobilePlatform::jsonb, '{MobilePlatform,enableTwoFactorAuth}', 'false');
In Postgres, the plain concatenation operator || for jsonb could do it:
UPDATE mytable
SET value = value::jsonb || '{"enableTwoFactorAuth":false}'::jsonb
WHERE name = 'MobilePlatform';
If a top-level key "enableTwoFactorAuth" already exists, it is replaced. So it's an "upsert" really.
Or use jsonb_set() for manipulating nested values.
The cast back to text works implicitly as assignment cast. (Results in standard format; any insignificant whitespace is removed effectively.)
If the content is valid JSON, the storage type should be json to begin with. In Postges, jsonb would be preferable as it's easier to manipulate, but that's not directly portable to the other two RDBMS mentioned.
(Or, possibly, a normalized design without JSON altogether.)
For ORACLE 21
update mytable
set json_col = json_transform(
json_col,
INSERT '$.value.enableTwoFactorAuth' = 'false'
)
where json_exists(json_col, '$?(#.name == "MobilePlatform")')
;
With json_col being JSON or VARCHAR2|CLOB column with IS JSON constraint.
(but must be JSON if you want a multivalue index on json_value.name:
create multivalue index ix_json_col_name on mytable t ( t.json_col.name.string() );
)
Two of the databases you are using support JSON data type, so it doesn't make sense to have them as stringified JSON object in a Text column.
Oracle: https://docs.oracle.com/en/database/oracle/oracle-database/21/adjsn/json-in-oracle-database.html
PostgreSQL: https://www.postgresql.org/docs/current/datatype-json.html
Apart from these, MSSQL Server also provides methods to work with JSON data type.
MS SQL Server: https://learn.microsoft.com/en-us/sql/relational-databases/json/json-data-sql-server?view=sql-server-ver16
Using a JSON type column in any of the above databases would enable you to use their JSON functions to perform the tasks that you are looking for.
If you've to use Text only then you can use replace to add the key-value pair at the end of your JSON
update dataTable set value = REPLACE(value, '}',",\"enableTwoFactorAuth\": false}") where name = 'MobilePlatform'
Here dataTable is the name of table.
The cleaner and less riskier way would be connect to db using the application and use JSON methods such as JSON.parse in Javascript and JSON.loads in Python. This would give you the JSON object (dictionary in case of Python) to work on. You can look for similar methods in other languages as well.
But i would suggest, if possible use JSON columns instead of Text to store the JSON value wherever possible.

Updating one row in JSON stored in MySQL

I've got a longtext field in my MySQL database that contains JSON strings. I'd like to be able to update only one row in the string rather than have to reinsert the entire thing updated.
How can I do that? I'm using Laravel but could do a raw query if needed.
(This is the first time I'm using JSON, so if I'm not using the right terminolgoy, forgive me.)
Your column needs to be of json type. then you can use the JSON_SET to set a aprticular json key in your payload.
example :
update table SETjson_column= JSON_SET(json_column, '$.\"$key\"' , 'foo') where id = 1;

MySQL getting JSON value

In my MySql players table I have a column called achievements and it is a text field which in this particular row has this value:
[
{
"value":11,
"globalID":23000000
},
{
"value":11,
"globalID":23000001
},
{
"value":11,
"globalID":23000002
},
...
{
"value":6044730,
"globalID":23000065
}
]
Near the bottom of the array you can see this object:
{
"value":48,
"globalID":23000062
},
I need to be able to parse the value field and show it as a warhero field. But how can I do this? The globalID will stay the same but the value changes. And because the globalID is after the value value I can't use what was used in this post: https://stackoverflow.com/a/21596032/4942382
What SQL query would I need to run to get that value?
Thanks!
The design of a table does not even meet the first normalisation level if it stores a non-atomic value in a single column, which is the case with this type of JSON encoded values.
Now if you have no access to the JSON functions available to MySql version 5.7+, and your globalID has a fixed number of digits, then you could do some string matching as follows.
For example, if you need the value that goes with globalID 23000062, then you could do this:
SELECT players.*,
CAST(
SUBSTRING_INDEX(
SUBSTRING_INDEX(achievements, '"globalID":23000062', 1),
'"value":',
-1
)
AS UNSIGNED) AS json_extracted_value
FROM players
WHERE INSTR(achievements, '"globalID":23000062') > 0
But really, you should seriously consider redesigning your database.
You should have never saved the JSON in your table, you already broke the rules of relational database design.
mysql cannot make sense of the data, so no SQL query will help you, you have 2 options:
Fix your database design, create tables to hold that data instead of JSON
Fetch the data, decode the JSON, and do all type of manipulations and hacks to get your desired value.

Correct xpath when reading JSON out of MYSQL DB using common_schema.extract_json

I am creating a query to re-use periodically to pull data out of a MySQL database (not for use in production code) and want to display values from a JSON object as columns. I installed common_schema and have been using the extract_json function but I can't find the correct xpath to use to get the field I want, I always get null. The query I am using currently is below:
SELECT common_schema.extract_json_value(stores.info,'/Region') as "Sales Region" FROM stores
An example of the JSON object stored in stores.info is below:
{"Town":"HDM","Post Code":"003408","Region":"FGH","OutletCode":"AB43G","CustomerCode":"15134158"}
What xpath do I need to access, for example Region. If the path is correct why is it returning NULL?

solr update with json causes 'error parsing json field. unexpected object_start'

I downloaded solr 4.6.1 and I am attempting to update the solr index using the following via command line:
curl http://localhost:8983/solr/update?commit=true -H 'Content-type:application/json' -d '
[{
"id" : "1",
"phoneNumber_ss": [{"foo_ss" : "bar"}]
}]
'
I am using the example schema.xml, which is why i used all the "_ss" fields.
The issue is that when I execute this I get the following response:
{"responseHeader":{"status":400,"QTime":1},"error":{"msg":"Error parsing JSON field value. Unexpected OBJECT_START","code":400}}
This seems to be related to the value specified for phoneNumber_ss field which is an array of objects. If I make the value into an array or an object it works fine, its only when it is an array of objects that the issue occurs.
Any help is much appreciated.
I don't think Solr support storing objects into a multivalued field. You can store it as a array of string. You might also store the object as a string and parse it in your application.
If you have such use case that you want to have all the objects from Solr only, you can follow the steps..
Create a multivalued field for your keys.
Maintain the same order of keys and create another multivalued field for values.
So, you can get the keys and values in same order in different fields. But in this approach you might face problems while updating those multivalued fields. You might want to look here
And finally, you are also missing some syntax in your update statement.
set – set or replace a particular value, or remove the value if null is specified as the new value
add – adds an additional value to a list
Check http://wiki.apache.org/solr/UpdateJSON