<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anh Nguyen</title>
    <description>The latest articles on DEV Community by Anh Nguyen (@anhhatesjava).</description>
    <link>https://dev.to/anhhatesjava</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F833186%2Fe43ba384-06a1-4ccf-8df6-f48314c27d3d.jpeg</url>
      <title>DEV Community: Anh Nguyen</title>
      <link>https://dev.to/anhhatesjava</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anhhatesjava"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Anh Nguyen</dc:creator>
      <pubDate>Sat, 01 Mar 2025 10:22:24 +0000</pubDate>
      <link>https://dev.to/anhhatesjava/-3o0a</link>
      <guid>https://dev.to/anhhatesjava/-3o0a</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/anhhatesjava" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F833186%2Fe43ba384-06a1-4ccf-8df6-f48314c27d3d.jpeg" alt="anhhatesjava"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/anhhatesjava/stop-one-by-one-inserts-bulk-insert-data-in-rails-with-insertall-or-activerecord-import-335o" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Stop One-By-One Inserts! Bulk Insert Data In Rails With insert_all Or activerecord-import ⚡&lt;/h2&gt;
      &lt;h3&gt;Anh Nguyen ・ Mar 1&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#rails&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#database&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#performance&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>rails</category>
      <category>database</category>
      <category>performance</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Stop One-By-One Inserts! Bulk Insert Data In Rails With insert_all Or activerecord-import ⚡</title>
      <dc:creator>Anh Nguyen</dc:creator>
      <pubDate>Sat, 01 Mar 2025 05:42:34 +0000</pubDate>
      <link>https://dev.to/anhhatesjava/stop-one-by-one-inserts-bulk-insert-data-in-rails-with-insertall-or-activerecord-import-335o</link>
      <guid>https://dev.to/anhhatesjava/stop-one-by-one-inserts-bulk-insert-data-in-rails-with-insertall-or-activerecord-import-335o</guid>
      <description>&lt;p&gt;If your CSV import is slower than dial-up internet, discover how bulk inserts can rocket your Rails performance. 🐢&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;1. Why Bulk Inserts Matter?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When dealing with large datasets for example, you want to import a CSV containing more than a thousand of tasks from your department, inserting records one by one (&lt;code&gt;.create&lt;/code&gt; or &lt;code&gt;.save&lt;/code&gt;) can &lt;strong&gt;drastically slow down performance&lt;/strong&gt; and cause &lt;strong&gt;database bottlenecks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine inserting &lt;strong&gt;100,000 records&lt;/strong&gt;—doing it traditionally means &lt;strong&gt;100,000 separate queries&lt;/strong&gt;!  Instead, &lt;strong&gt;bulk inserting&lt;/strong&gt; reduces this to a &lt;strong&gt;single efficient query&lt;/strong&gt;, saving time and resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;2. Prerequisites&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before diving in, ensure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're using &lt;strong&gt;Rails 6+&lt;/strong&gt; for &lt;code&gt;insert_all&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You have the &lt;strong&gt;&lt;code&gt;activerecord-import&lt;/code&gt; gem&lt;/strong&gt; installed if using an older version which supports Rails 3.x&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;3. Step-by-Step Guide&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 The Problem With Each-By-Each Inserts
&lt;/h3&gt;

&lt;p&gt;For example, you want to create 100k records of tasks by a naive way, this is how it look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="c1"&gt;# Create 100k records each times&lt;/span&gt;
  &lt;span class="mi"&gt;100_000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create!&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Task &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"This is description of task &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;is_finished: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I did some benchmark here with this snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="n"&gt;execution_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="mi"&gt;100_000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create!&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Task &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"This is description of task &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;is_finished: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Execution time: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;execution_time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;real&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; seconds"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl6t0vo4sn7nwsjfkwsqp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl6t0vo4sn7nwsjfkwsqp.png" alt="Benchmark One-by-One" width="800" height="137"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image shows that the execution of record creation takes &lt;b&gt;20.99 seconds&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;✅ Pros:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Models validation or callbacks works&lt;/strong&gt; - &lt;code&gt;the name field is not null but there is a call with null name, the insert will be raise with errors&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Older Rails versions &amp;lt; 6.0 support&lt;/strong&gt; - Legacy project without bulk insert support.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;❌ Cons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Performance Issue&lt;/strong&gt; - Each insert requires a separate database transaction, increasing overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased Network Traffic&lt;/strong&gt; - 100k request will be made into the database which increases network costs.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3.2 Solution 1: Use &lt;code&gt;insert_all&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;insert_all&lt;/code&gt; method allows you to insert &lt;strong&gt;multiple records at once&lt;/strong&gt;, significantly boosting performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: Using &lt;code&gt;insert_all&lt;/code&gt; for create 100k tasks&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="c1"&gt;# Initialize 100k tasks hash then add to tasks array&lt;/span&gt;
  &lt;span class="mi"&gt;100_000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Task &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"This is description of task &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;is_finished: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# Bulk insert all the initialized tasks&lt;/span&gt;
  &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10hldrhu59rurxknfnu1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10hldrhu59rurxknfnu1.png" alt="Insert All" width="800" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✅ Pros:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Faster than &lt;code&gt;.create&lt;/code&gt;&lt;/strong&gt; - Single SQL query&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rails built-in method&lt;/strong&gt; -  Bulk operations directly in Rails without extra gems.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;❌ Cons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Does not accept ActiveRecord models&lt;/strong&gt; – Only works with raw hashes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bypasses model validations and callbacks&lt;/strong&gt; – Data integrity must be handled manually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cannot handle associations automatically&lt;/strong&gt; – Requires extra queries to fetch related IDs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: Inserting &lt;code&gt;Tasks&lt;/code&gt; that Belong to &lt;code&gt;Department&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="n"&gt;departments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Marketing"&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; 
  &lt;span class="n"&gt;department&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Department&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;departments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="n"&gt;department_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;department&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt; &lt;span class="c1"&gt;# Error raised&lt;/span&gt;

  &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Task 0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"This is the task description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;is_finished: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;department_id: &lt;/span&gt;&lt;span class="sc"&gt;??&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="c1"&gt;# missing department_id here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F14ic9e576eoww4sbnvpx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F14ic9e576eoww4sbnvpx.png" alt="No ID returns error exception" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image shows that no id can be returned after using &lt;b&gt;insert_all&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Fix&lt;/strong&gt;: Manually retrieve &lt;code&gt;department_id&lt;/code&gt; before inserting &lt;code&gt;tasks&lt;/code&gt;, &lt;em&gt;adding an extra query.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="n"&gt;department&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Department&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Marketing"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# cost a SQL query&lt;/span&gt;
  &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Task 0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"This is the task description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;is_finished: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;department_id: &lt;/span&gt;&lt;span class="n"&gt;department&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.3 Solution 2: Best of both worlds - Use &lt;code&gt;activerecord-import&lt;/code&gt; gem
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;import&lt;/code&gt; method allows you to insert models with associations&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: Using &lt;code&gt;import&lt;/code&gt; to create 100k tasks in 1 department&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="n"&gt;department&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Department&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Marketing"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="mi"&gt;100_000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Task &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"This is description of task &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;is_finished: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;department&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;

  &lt;span class="n"&gt;execution_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Department&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;import&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;department&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Execution time: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;execution_time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;real&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; seconds"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Able to import 1 department with 100k tasks with the use of Active Record Import&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ngj6v4m67z1fmgnyuti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ngj6v4m67z1fmgnyuti.png" alt="Association Import" width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Observe the performance compared to &lt;code&gt;insert_all&lt;/code&gt; is similar to each other ( About 1.44 seconds )&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9jsw2j9h4w1grc3gsef.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9jsw2j9h4w1grc3gsef.png" alt="Activerecord-import benchmark" width="800" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✅ Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Works with raw columns and arrays of values (fastest)&lt;/li&gt;
&lt;li&gt;Works with model objects (faster)&lt;/li&gt;
&lt;li&gt;Performs validations (fast)&lt;/li&gt;
&lt;li&gt;Performs on duplicate key updates (requires MySQL, SQLite 3.24.0+, or Postgres 9.5+)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❌ Cons:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Need an extra gem installed&lt;/li&gt;
&lt;li&gt;ActiveRecord callbacks related to &lt;a href="http://guides.rubyonrails.org/active_record_callbacks.html#creating-an-object" rel="noopener noreferrer"&gt;creating&lt;/a&gt;, &lt;a href="http://guides.rubyonrails.org/active_record_callbacks.html#updating-an-object" rel="noopener noreferrer"&gt;updating&lt;/a&gt;, or &lt;a href="http://guides.rubyonrails.org/active_record_callbacks.html#destroying-an-object" rel="noopener noreferrer"&gt;destroying&lt;/a&gt; records (other than &lt;code&gt;before_validation&lt;/code&gt; and &lt;code&gt;after_validation&lt;/code&gt;) will NOT be called when calling the import method. ( calling separately with &lt;code&gt;run_callbacks&lt;/code&gt; as recommended )&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;4. Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;One rule to remember when inserting a large number of records ( Example: Import a large number of records from a CSV file ) is to avoid creating records one-by-one. Instead, we can consider using &lt;code&gt;activerecord-import&lt;/code&gt; or &lt;code&gt;insert_all&lt;/code&gt; for a great performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;5. Reference&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;activerecord-import: &lt;a href="https://github.com/zdennis/activerecord-import" rel="noopener noreferrer"&gt;https://github.com/zdennis/activerecord-import&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;insert_all: &lt;a href="https://apidock.com/rails/v6.0.0/ActiveRecord/Persistence/ClassMethods/insert_all" rel="noopener noreferrer"&gt;https://apidock.com/rails/v6.0.0/ActiveRecord/Persistence/ClassMethods/insert_all&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rails</category>
      <category>database</category>
      <category>performance</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The Pitfalls of Custom Enum Ordering in Prisma Compared to TypeORM &amp; MikroORM</title>
      <dc:creator>Anh Nguyen</dc:creator>
      <pubDate>Sun, 02 Feb 2025 05:11:12 +0000</pubDate>
      <link>https://dev.to/anhhatesjava/the-pitfalls-of-custom-enum-ordering-in-prisma-compared-to-typeorm-mikroorm-4a9e</link>
      <guid>https://dev.to/anhhatesjava/the-pitfalls-of-custom-enum-ordering-in-prisma-compared-to-typeorm-mikroorm-4a9e</guid>
      <description>&lt;p&gt;"Who use Prisma in production?" The statement is true in my daily work. During my work on a project with Prisma as ORM, whenever I worked on a feature, I usually get lots of open issues which blocks my development and getting things done.&lt;/p&gt;

&lt;p&gt;I came up with this article based on my curiosity on how other ORM can handle the mapping of fields and custom enum ordering equally well. We’ll walk through the steps, highlight the issue, and compare Prisma with its counterparts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step-by-Step Guide
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Understanding the requirement
&lt;/h3&gt;

&lt;h3&gt;
  
  
  1.1 Custom ordering requirement
&lt;/h3&gt;

&lt;p&gt;Modern ORMs offer a convenient way to sort by specific fields or enum indices. This is especially handy when you have an enum that represents a strict order (like priority levels: &lt;code&gt;LOW&lt;/code&gt;, &lt;code&gt;MEDIUM&lt;/code&gt;, &lt;code&gt;HIGH&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why this matters&lt;/strong&gt;: If you want items always ordered by &lt;code&gt;HIGH&lt;/code&gt; first, then &lt;code&gt;MEDIUM&lt;/code&gt;, then &lt;code&gt;LOW&lt;/code&gt;, you might rely on the enum’s internal indexing or a custom field to achieve consistent sorting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1.2 Mapped fields requirement
&lt;/h3&gt;

&lt;p&gt;Prisma maps fields in your schema (e.g., &lt;code&gt;someField&lt;/code&gt;) to columns in your database (e.g., &lt;code&gt;some_field&lt;/code&gt;). Under most circumstances, Prisma automatically translates the naming between your application layer (camelCase) and your database layer (snake_case).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why this matters&lt;/strong&gt;: SQL is case-insensitive, and many databases automatically convert unquoted identifiers to lowercase when creating tables. This means that any capitalization used in camelCase is lost, obscuring the intended separation between words. Using snake_case ensures that word boundaries are clearly maintained, making your database schema more portable and consistent across different SQL databases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. The Drawback: Using Raw SQL for Custom Enum Order
&lt;/h3&gt;

&lt;p&gt;When you need to order by an enum’s indexed order that isn’t directly supported by Prisma’s standard query capabilities, you might resort to a custom raw SQL query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$queryRaw&lt;/span&gt;&lt;span class="s2"&gt;`
    SELECT * 
    FROM tasks
    ORDER BY 
      CASE 
        WHEN severity = HIGH THEN 1
        WHEN severity = NORMAL THEN 2
        WHEN severity = LOW THEN 3
        ELSE 999999
      END,
      created_at DESC
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The issue&lt;/strong&gt;: The result returned from &lt;code&gt;prisma.$queryRaw&lt;/code&gt; will not automatically map column names from &lt;code&gt;snake_case&lt;/code&gt; to &lt;code&gt;camelCase&lt;/code&gt;. This means you end up with fields like &lt;code&gt;my_enum_column&lt;/code&gt; in your JavaScript objects instead of the expected &lt;code&gt;myEnumColumn&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Why This Becomes a Problem
&lt;/h3&gt;

&lt;p&gt;When your application logic expects a property named &lt;code&gt;myEnumColumn&lt;/code&gt; (camelCase), but the database returns &lt;code&gt;my_enum_column&lt;/code&gt; (snake_case), you have to manually handle that conversion. This extra step can introduce errors or force you to create unnecessary helper functions to remap fields.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistent Code&lt;/strong&gt;: You’ll have to remember which parts of your code deal with raw SQL (snake_case) versus Prisma’s default query system (camelCase).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extra Boilerplate&lt;/strong&gt;: You might add transformations to your service layer just to rename fields properly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Alternatives in TypeORM or MikroORM
&lt;/h3&gt;

&lt;p&gt;Other ORMs such as &lt;strong&gt;TypeORM&lt;/strong&gt; or &lt;strong&gt;MikroORM&lt;/strong&gt; often provide decorators or built-in mechanisms to handle custom ordering directly in their &lt;strong&gt;query builder&lt;/strong&gt; or &lt;strong&gt;entity configuration&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TypeORM&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;createQueryBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;task&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
    CASE 
      WHEN severity = "HIGH" THEN 1
      WHEN severity = "MEDIUM" THEN 2
      WHEN severity = "LOW" THEN 3
    END
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ASC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Even if it involves writing some SQL logic, TypeORM’s query builder often keeps the field mapping in sync with your entity definitions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MikroORM&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;caseExpression&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    CASE 
      WHEN severity = "HIGH" THEN 1
      WHEN severity = "MEDIUM" THEN 2
      WHEN severity = "LOW" THEN 3
    END
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;em&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;caseExpression&lt;/span&gt;&lt;span class="p"&gt;)]:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ASC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;MikroORM’s entity definitions and naming strategies often ensure consistent field naming without requiring raw SQL queries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why They Might Work Better&lt;/strong&gt;: In these ORMs, you often define the enum fields and the ordering logic in your entity configuration (ex: &lt;code&gt;Task.entity.ts&lt;/code&gt;). If you write a custom expression, you’re still able to leverage the ORM’s mapping layer, thus avoiding the mismatch of &lt;code&gt;camelCase&lt;/code&gt; vs. &lt;code&gt;snake_case&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. My workarounds in Prisma
&lt;/h3&gt;

&lt;p&gt;If you’re heavily invested in Prisma and still want to achieve custom enum ordering without dealing with mismatched field names:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write a small utility function that converts &lt;code&gt;snake_case&lt;/code&gt; keys to &lt;code&gt;camelCase&lt;/code&gt; after you execute a raw SQL query, ensuring consistency.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CamelCase&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;P1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;P2&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;P3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Lowercase&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nb"&gt;Uppercase&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;CamelCase&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Lowercase&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CamelizeKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;CamelCase&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;camelize&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;CamelizeKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasOwnProperty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;camelKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/_&lt;/span&gt;&lt;span class="se"&gt;([&lt;/span&gt;&lt;span class="sr"&gt;a-z&lt;/span&gt;&lt;span class="se"&gt;])&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;letter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;letter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;camelKey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Handling custom enum ordering is a common need in many applications. With TypeORM or MikroORM, you can often maintain a consistent field mapping while still using a flexible &lt;strong&gt;query builder&lt;/strong&gt; for sorting. Prisma, however, requires a raw SQL approach for more complex enum sorting logic, leading to a mismatch between &lt;code&gt;camelCase&lt;/code&gt; properties in your application and &lt;code&gt;snake_case&lt;/code&gt; columns in your database.&lt;/p&gt;

&lt;p&gt;I encourage you to try out these steps and see which approach works best in your application. Try to avoid using Prisma on production, you can consider 2 options above to help your application get things done.&lt;/p&gt;

</description>
      <category>prisma</category>
      <category>typescript</category>
      <category>database</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
