Facebook iconUpdating JSON Columns in Ruby on Rails
WhatsApp Icon (SVG)
BlogsTechnologyStrategies for Updating JSON Columns in Ruby on Rails

Strategies for Updating JSON Columns in Ruby on Rails

Feb 9, 20245 min read
by Piyush Duragkar
Strategies for Updating JSON Columns in Ruby on Rails Hero

Ruby on Rails is a framework that has become popular in the dynamic field of web development for creating scalable and reliable applications. JSON columns are supported by ROR, giving developers an effective method for working with deeply nested or complex structured data.

Updating JSON columns in ROR applications has many benefits, but there are some challenges that developers must successfully overcome. We'll look at some of the typical problems that arise while modifying JSON columns in Ruby on Rails apps in this blog post, along with solutions.

Challenges in updating JSON columns

JSON columns are convenient and flexible, and their structure makes it difficult to update them in Rails applications. When modifying JSON columns, developers frequently run into the following issues:

Nested Data:  JSON columns frequently have nested data which makes it difficult to update individual nested attributes without erasing the entire JSON object. Also, we have to ensure that updates are applied on the correct key. Here is sample JSON column data.

Concurrency: Simultaneous updates to the same JSON column can lead to concurrency issues.

Validation: It can be difficult to validate JSON data, particularly when conditional validation rules and hierarchical structures are involved.

In the above example, the User’s email should be present and unique. The validation makes sure that the name of each User record is distinct from all other User entries and is not empty.

In the above example, the profile is a JSON column. Because of the nested nature of JSON data, it may be difficult to add validation to individual keys within JSON data. If we want to apply presence validation on a specific key of JSON data, then we have to write custom validation for it.

Also applying uniqueness validation would be custom only, as first, we have retrieved it and compared it with the rest of the JSON data.

Querying and Indexing: If we compared our normal relational columns, JSON columns in the database might not be as effective for querying and indexing. To increase performance, you might need to carefully optimize your queries and carefully think about creating appropriate indexes for JSON columns.

In ROR we can add indexes to our columns using migration.

In the above example, add_index or CREATE INDEX is used to create an index on a profile column for a specific key key_to_index within the JSON data, using the ->> operator to fetch the value as a string, and the using::gin option specifies that the Generalized Inverted Index (GIN) method should be used, which is capable for indexing JSON columns in PostgreSQL.

Partial update: Rails has functionality for updating specific columns. It has activerecord methods such as update_column or update_columns. But It doesn't provide us with a specific nested key attribute to update. Every time updating an entire JSON column updates the whole JSON document, which is very inefficient and makes complex database operations. Rails retrieves the entire JSON document from the database, modifies it in memory, and then stores the entire document back into the database. Also, there is no built-in support at the database level for partially updating keys in certain JSON documents, resulting in inefficient data transfers.

Strategies for Overcoming Hurdles

It can be difficult to validate JSON data, particularly when conditional validation rules and hierarchical structures are involved.

Use of ActiveRecord methods

Rails has activerecords methods like update_column & update_columns for updating specific columns without triggering callbacks or validations. It helps to update specific attributes. It will be helpful when JSON data is smaller.

But when we talk about updating specific JSON columns, we will face a similar issue that we discussed above.

Utilizing Database function

When it comes to changing JSON columns in Rails, utilizing database functions usually means modifying JSON data in the database using SQL commands or certain functions offered by the DBMS instead of depending only on Rails ActiveRecord methods. This method is especially helpful in situations when it's important to optimize efficiency or when the changes require intricate manipulations of nested JSON structures.

Let's take an example: In a Rails application, we have a user_courses table containing a JSON column named progress storing user progress related to course information. Let's consider we want to update a specific attribute within the progress column for a user_course with a given content_id. Instead of fetching the entire JSON data, modifying it in rails code, and then saving it back to the DB, we can use database functions to perform the update directly in SQL.

Here's an example of using the MYSQL JSON_SET function to update a nested attribute within the JSON column.

Here's an example of using PostgreSQL's jsonb_set function to update a nested attribute within the JSON column.

In the above examples

  • UserCourses represents a table with a column named progress.
  • JSON_SET(data, '{$.nested_key}', '#{new_value}') is the MYSQL function that sets the value of the specified nested key within the data JSON column to the new_value.
  • JSONB_SET(data, '{nested_key}', '#{new_value}') is the PostgreSQL function that sets the value of the specified nested key within the data JSON column to the new_value.

Let's take the example of a nested attribute:

Existing progress column

Query Execution

After query execution

In the above example, we are updating the "status" and "progress_in_sec" within the specific key "_148". '$._148.status' '$._148.progress_in_sec' are representing the same. 

Better performance: Database operations are optimized for data manipulation resulting in faster updates compared to fetching and updating JSON data in a Rails application.

Less data transfer: Since updates are done directly at the database level, large JSON objects do not need to be transferred between the application and the database, reducing network overhead.

Atomicity and consistency: Database operations ensure that updates are performed atomically in a single transaction, maintaining data consistency and integrity.

This function is useful when you want to update individual attributes of a JSON column without overwriting the entire JSON document.

So, using database queries to update JSON columns in Rails applications provides a more efficient and better approach, especially for scenarios involving complex JSON data.

Conclusion:

Working with JSON columns in Ruby on Rails (ROR) can be tricky when it comes to updating them. Dealing with nested data, concurrency, and validation issues can be a headache.

To make life easier, developers have options. They can use basic Rails methods for simple updates, but for more precise changes, tapping into database functions like JSON_SET in MySQL or jsonb_set in PostgreSQL is the way to go.

This smarter approach speeds things up, cuts down on data back and forth, and ensures that updates happen smoothly and reliably. 

So, when dealing with complex JSON data in ROR apps, taking advantage of these database functions is definitely the way forward.

Author Detail

Author-Piyush Duragkar
Piyush Duragkar

Backend Developer with 3+years of experience with Ruby on Rails. Specialising in backend optimisation, API development, and database. Enthusiastic about developing scalable, effective solutions.

Phone

Next for you