<?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: Alexander Fridriksson</title>
    <description>The latest articles on DEV Community by Alexander Fridriksson (@datastorydesign).</description>
    <link>https://dev.to/datastorydesign</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%2F795669%2F55f865a8-4ce9-4f83-babd-5c867c365399.png</url>
      <title>DEV Community: Alexander Fridriksson</title>
      <link>https://dev.to/datastorydesign</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/datastorydesign"/>
    <language>en</language>
    <item>
      <title>Building Smarter Product Recommendations with SurrealDB</title>
      <dc:creator>Alexander Fridriksson</dc:creator>
      <pubDate>Thu, 06 Mar 2025 13:36:56 +0000</pubDate>
      <link>https://dev.to/surrealdb/building-smarter-product-recommendations-with-surrealdb-n82</link>
      <guid>https://dev.to/surrealdb/building-smarter-product-recommendations-with-surrealdb-n82</guid>
      <description>&lt;p&gt;Personalised experiences can make or break the conversion of a visitor into a customer, which is why recommendation engines are no longer a luxury — they’re essential. &lt;/p&gt;

&lt;p&gt;You’ve seen them everywhere:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“&lt;em&gt;Gift ideas inspired by your shopping history.&lt;/em&gt;”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Customers who viewed this item also bought…”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Just arrived for you.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, behind these helpful nudges are complex systems. Traditionally, building these systems meant building out a team of experts who build out stacks of disconnected tools, which then need to be glued together again. This might include relational, document and graph databases along with advanced machine learning and vector stores.&lt;/p&gt;

&lt;p&gt;Systems like these trend toward ever increasing complexity, but is that really necessary?&lt;/p&gt;

&lt;p&gt;What if complex systems don’t need to be complicated?&lt;/p&gt;

&lt;p&gt;What if you could do it all in one stack?&lt;/p&gt;

&lt;h2&gt;
  
  
  Unify disconnected tools with SurrealDB
&lt;/h2&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%2Fs2rww1inglduvrmvjyk5.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%2Fs2rww1inglduvrmvjyk5.png" alt="SurrealDB gives you the power of 10+ products in one unified multi-model database." width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SurrealDB gives you the power of 10+ products in one unified multi-model database.&lt;/p&gt;

&lt;p&gt;It's natively real-time, relational, document, graph, vector and more. Built from the ground up using cutting-edge research and the Rust language to ensure runtime safety, combined with the performance and low-latency requirements you need from a high performance system.&lt;/p&gt;

&lt;p&gt;For recommendation systems, this enables you to build simpler systems and achieve better personalisation. Instead of juggling multiple systems to stitch together context, relationships, and meaning, SurrealDB lets you keep everything in one tightly integrated platform, without the need to install or interact with multiple databases, libraries or frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Recommendations Need to Be Smarter
&lt;/h2&gt;

&lt;p&gt;Traditional recommendation systems rely on techniques like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Collaborative Filtering (CF):&lt;/strong&gt; "People who bought this also bought…"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content-Based Filtering:&lt;/strong&gt; "Products similar to the ones you like."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid Models:&lt;/strong&gt; Combining CF and content-based for more accuracy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These work, but if you could increase conversion rates by a few percent, why wouldn’t you?&lt;/p&gt;

&lt;p&gt;The current cutting-edge trends are moving towards real-time, more context-aware systems - making using of LLM driven recommendations powered by centralised knowledge graphs.&lt;/p&gt;

&lt;p&gt;This is where SurrealDB shines. Let’s therefore explore a high-level recipe for how you can build such recommendation systems, simply using SurrealDB and an LLM provider. No need for Python glue code, frameworks, vector stores and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Build a Smart Recommendation Engine with SurrealDB
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Build Out Your Knowledge Graph
&lt;/h3&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%2Ff74mq04qzdalv7q5adzk.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%2Ff74mq04qzdalv7q5adzk.png" alt="Surreal Deal Store" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This makes it easy to provide context that can be used to answer questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who bought what? &lt;/li&gt;
&lt;li&gt;Who’s similar to whom? &lt;/li&gt;
&lt;li&gt;What’s trending?
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="k"&gt;distinct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;recommended_products&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="n"&gt;FVRH055G93BAZDEVNAJ9ZG3D&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Turn Data Into Embeddings for Vector Search and LLMs
&lt;/h3&gt;

&lt;p&gt;Create vector embeddings from product descriptions or user behaviour.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;create_embeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&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="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"https://example.com/api/embeddings"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"embedding model"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;input&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;p&gt;These embeddings unlock semantic search, so you can say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Show me products similar to a ‘casual sweatshirt’”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And get results based on meaning, not just keywords.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;similarity&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cosine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;details_embedding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;similarity&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mix Semantic Search with Full-Text Search
&lt;/h3&gt;

&lt;p&gt;Combine keyword relevance and vector similarity for the best of both worlds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;hybrid_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;search_term&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;create_embeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;search_term&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;semantic_search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;full_text_search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;semantic_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;semantic_search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;full_text_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;full_text_search&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;h3&gt;
  
  
  Add Context from the Graph
&lt;/h3&gt;

&lt;p&gt;Retrieve personalised context: purchase history, preferences, popular items, and more.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;person_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;record_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;order_history&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;record_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;context&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;h3&gt;
  
  
  Send the context to an LLM
&lt;/h3&gt;

&lt;p&gt;Send all this rich context into an LLM for hyper-personalised recommendations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get_recs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;any&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="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://example.com/api/chat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'reasoning model'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;template&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;
  
  
  A Real-World Example: Luxury Fashion Retail
&lt;/h2&gt;

&lt;p&gt;A luxury fashion retailer was struggling with low website conversion rates. They had personal shoppers in-store, but scaling that experience online was a massive challenge.&lt;/p&gt;

&lt;p&gt;Their solution? Build a virtual personal shopper!&lt;/p&gt;

&lt;h4&gt;
  
  
  The Results:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;4 million customers served monthly&lt;/li&gt;
&lt;li&gt;1.5 million recommendations every week&lt;/li&gt;
&lt;li&gt;3x increase in conversion rates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By creating a real-time recommendation pipeline powered end-to-end by SurrealDB. Want to see it in action? Check out the full case study on &lt;a href="https://www.youtube.com/watch?v=yLw9MvNfuY8" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Want help making your recommendations smarter? &lt;a href="https://surrealdb.com/contact" rel="noopener noreferrer"&gt;Reach out to us&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Challenge accepted: announcing SurrealDB 2.0</title>
      <dc:creator>Alexander Fridriksson</dc:creator>
      <pubDate>Tue, 17 Sep 2024 15:40:55 +0000</pubDate>
      <link>https://dev.to/surrealdb/challenge-accepted-announcing-surrealdb-20-52b1</link>
      <guid>https://dev.to/surrealdb/challenge-accepted-announcing-surrealdb-20-52b1</guid>
      <description>&lt;p&gt;When we &lt;a href="https://surrealdb.com/blog/announcing-surrealdb-1-0" rel="noopener noreferrer"&gt;announced our 1.0 release&lt;/a&gt;, we planted our flag in the database world as a new and upcoming database with the potential of being &lt;a href="https://surrealdb.com/blog/why-surrealdb-is-the-future-of-database-technology--an-in-depth-look" rel="noopener noreferrer"&gt;the future of database technology&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With the massive community adoption that followed came massive expectations and challenges to live up to these expectations.&lt;/p&gt;

&lt;p&gt;However, the people of SurrealDB - employees and community champions, stepped up with a challenge accepted attitude and solved these challenges with our 2.0 release!&lt;/p&gt;

&lt;p&gt;We've made major improvements in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://surrealdb.com/blog/challenge-accepted-announcing-surrealdb-2-0/#stability-and-performance" rel="noopener noreferrer"&gt;Stability and performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://surrealdb.com/blog/challenge-accepted-announcing-surrealdb-2-0/#querying" rel="noopener noreferrer"&gt;Querying&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://surrealdb.com/blog/challenge-accepted-announcing-surrealdb-2-0/#security" rel="noopener noreferrer"&gt;Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://surrealdb.com/blog/challenge-accepted-announcing-surrealdb-2-0/#sdks" rel="noopener noreferrer"&gt;SDKs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://surrealdb.com/blog/challenge-accepted-announcing-surrealdb-2-0/#surrealml" rel="noopener noreferrer"&gt;SurrealML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://surrealdb.com/blog/challenge-accepted-announcing-surrealdb-2-0/#surrealkv" rel="noopener noreferrer"&gt;SurrealKV&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stability and Performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New SurrealQL parser
&lt;/h3&gt;

&lt;p&gt;We've rebuilt the SurrealQL parser from the ground up to be faster and more resilient. &lt;/p&gt;

&lt;p&gt;It addresses many of the shortcomings of the previous version, offering better error messages and overcoming the limitations of system stack constraints, ensuring that performance remains consistent even as query complexity increases.&lt;/p&gt;

&lt;p&gt;Unlike the previous parser, which was based on the &lt;a href="https://github.com/rust-bakery/nom" rel="noopener noreferrer"&gt;&lt;code&gt;nom&lt;/code&gt;&lt;/a&gt; parser-combinator library, the new parser is an optimised recursive descent parser with a separate lexing step. This change allows for more efficient parsing by separating the tokenisation of the input from the parsing logic itself, streamlining the parsing process.&lt;/p&gt;

&lt;p&gt;Additionally, the new parser includes new memory management techniques to ensure optimal resource usage, minimising memory overhead during parsing operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improved caching and transaction layer
&lt;/h3&gt;

&lt;p&gt;The new caching mechanisms introduced in 2.0 significantly improve the performance of SurrealDB by reducing the need to refetch data from the underlying storage engine. The caching layer stores the results of frequently executed requests, allowing subsequent processes to be served from the caching layer. This improvement in the core engine will help to speed up queries which select from and modify the database. &lt;/p&gt;

&lt;p&gt;In addition to the revamped transaction layer now providing better consistency and lower latency in distributed environments, which ensures your applications can seamlessly manage high-throughput workloads.&lt;/p&gt;

&lt;p&gt;We can see this in practice with our graph queries, where before each field needed to fetched individually and now we fetch them all at once. We have also added a nicer syntax for that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Before we used to fetch each field individually&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sub_category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="n"&gt;G07Z3RJ098G8GK8MCRZCPNF9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Now we fetch them all at once and have a nicer syntax as well&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sub_category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="n"&gt;G07Z3RJ098G8GK8MCRZCPNF9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Optimised index performance
&lt;/h3&gt;

&lt;p&gt;2.0 introduces several enhancements to indexing. These include improvements to hashing mechanisms, the addition of the &lt;a href="https://surrealdb.com/docs/surrealql/statements/define/indexes#hnsw-hierarchical-navigable-small-world" rel="noopener noreferrer"&gt;HNSW algorithm&lt;/a&gt; for AI-driven searches, and the option for &lt;a href="https://surrealdb.com/docs/surrealql/statements/define/indexes#using-concurrently-clause" rel="noopener noreferrer"&gt;asynchronous indexing&lt;/a&gt; and &lt;a href="https://surrealdb.com/docs/surrealql/statements/define/indexes#rebuilding-indexes" rel="noopener noreferrer"&gt;rebuilding indexes&lt;/a&gt;. These updates ensure that your queries are executed quickly, even as your data grows in complexity and volume.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Build the HNSW index without blocking operations&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;mt_pts&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;pts&lt;/span&gt; &lt;span class="n"&gt;FIELDS&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt; 
&lt;span class="n"&gt;HNSW&lt;/span&gt; &lt;span class="n"&gt;DIMENSION&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="n"&gt;DIST&lt;/span&gt; &lt;span class="n"&gt;EUCLIDEAN&lt;/span&gt; &lt;span class="n"&gt;EFC&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
&lt;span class="n"&gt;CONCURRENTLY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Rebuild the index&lt;/span&gt;
&lt;span class="n"&gt;REBUILD&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;mt_pts&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With all these advancements in stability and performance, SurrealDB 2.0 is more than just an upgrade to your database architecture - it's a platform built to handle the complex, high-performance needs of modern enterprises.&lt;/p&gt;

&lt;h2&gt;
  
  
  Querying
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SurrealQL enhancements
&lt;/h3&gt;

&lt;p&gt;In SurrealDB 2.0, we've made several improvements to our schema definitions such as the introduction of &lt;a href="https://surrealdb.com/docs/surrealql/statements/define/field#defining-a-literal-on-a-field" rel="noopener noreferrer"&gt;literal types&lt;/a&gt; to simplify the definition of complex types&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Before: define the object then define its contents one by one&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;FIELD&lt;/span&gt; &lt;span class="n"&gt;addresses&lt;/span&gt; 
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; 
    &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;FIELD&lt;/span&gt; &lt;span class="n"&gt;addresses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address_line_1&lt;/span&gt; 
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; 
    &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;FIELD&lt;/span&gt; &lt;span class="n"&gt;addresses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt; 
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; 
    &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;FIELD&lt;/span&gt; &lt;span class="n"&gt;addresses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt; 
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; 
    &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;FIELD&lt;/span&gt; &lt;span class="n"&gt;addresses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post_code&lt;/span&gt; 
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; 
    &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- After: define a literal type of an object and its contents&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;FIELD&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;address_line_1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;post_code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have also changed our default &lt;code&gt;DEFINE&lt;/code&gt; statement behaviour to only run once, with a new &lt;a href="https://surrealdb.com/docs/surrealql/statements/define/table#using-overwrite-clause" rel="noopener noreferrer"&gt;&lt;code&gt;OVERWRITE&lt;/code&gt; clause&lt;/a&gt; and &lt;a href="https://surrealdb.com/docs/surrealql/statements/alter" rel="noopener noreferrer"&gt;&lt;code&gt;ALTER&lt;/code&gt; statement&lt;/a&gt; for updating the schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Define a table or overite the definition if it exists&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;OVERWRITE&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;NORMAL&lt;/span&gt; &lt;span class="n"&gt;SCHEMALESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Make a specific change to a table definition&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="n"&gt;SCHEMAFULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Speaking of updating, we’ve also changed the default behaviour of the &lt;a href="https://surrealdb.com/docs/surrealql/statements/update" rel="noopener noreferrer"&gt;&lt;code&gt;UPDATE&lt;/code&gt; statement&lt;/a&gt; to update only and added a new &lt;a href="https://surrealdb.com/docs/surrealql/statements/upsert" rel="noopener noreferrer"&gt;&lt;code&gt;UPSERT&lt;/code&gt; statement&lt;/a&gt; for the previous create or update behaviour.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Will fail if the record doesn't exist&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="n"&gt;GRTTE7DG94R864R67MGDT0QM&lt;/span&gt; 
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"Surreal T-shirt"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Will create the record if it doesn't exist&lt;/span&gt;
&lt;span class="n"&gt;UPSERT&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="n"&gt;GRTTE7DG94R864R67MGDT0QM&lt;/span&gt; 
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"Surreal T-shirt"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GraphQL support
&lt;/h3&gt;

&lt;p&gt;SurrealDB 2.0 now has experimental support for &lt;a href="https://graphql.org/" rel="noopener noreferrer"&gt;GraphQL&lt;/a&gt;, which together with &lt;a href="https://surrealdb.com/docs/surrealdb/querying/graphql/surrealist" rel="noopener noreferrer"&gt;Surrealist&lt;/a&gt; makes querying with GraphQL not just possible but a delight.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- SurrealQL&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;

&lt;span class="c1"&gt;-- GraphQL&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;
        &lt;span class="n"&gt;price&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;p&gt;We’ve added automatic schema generation to enhance your experience. As you define your data models in GraphQL, Surrealist can automatically generate schemas for SurrealDB, saving you time and ensuring your database structure is always in sync with your application’s needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;CONFIG&lt;/span&gt; &lt;span class="n"&gt;GRAPHQL&lt;/span&gt; &lt;span class="n"&gt;AUTO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;CONFIG&lt;/span&gt; &lt;span class="n"&gt;GRAPHQL&lt;/span&gt; &lt;span class="n"&gt;TABLES&lt;/span&gt; &lt;span class="n"&gt;AUTO&lt;/span&gt; &lt;span class="n"&gt;FUNCTIONS&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;CONFIG&lt;/span&gt; &lt;span class="n"&gt;GRAPHQL&lt;/span&gt; &lt;span class="n"&gt;TABLES&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;]};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whether using SurrealQL or GraphQL, 2.0 offers powerful, flexible tools that make data management intuitive and efficient for your applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Overhauled security framework
&lt;/h3&gt;

&lt;p&gt;Security has been a major focus in 2.0, with significant enhancements aimed at providing robust protection and secure access to your data. Much of this is thanks to your input!&lt;/p&gt;

&lt;p&gt;The introduction of the &lt;a href="https://surrealdb.com/docs/surrealql/statements/define/access" rel="noopener noreferrer"&gt;&lt;code&gt;DEFINE ACCESS&lt;/code&gt;&lt;/a&gt; statement, which replaces &lt;a href="https://surrealdb.com/docs/surrealql/statements/define/scope" rel="noopener noreferrer"&gt;&lt;code&gt;DEFINE SCOPE&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://surrealdb.com/docs/surrealql/statements/define/token" rel="noopener noreferrer"&gt;&lt;code&gt;DEFINE TOKEN&lt;/code&gt;&lt;/a&gt;, offers greater control over user authentication, session management, and using 3rd-party authentication providers. These changes ensure that your databases are secure by default, with options for fine-tuning security settings to meet your specific needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;ACCESS&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;RECORD&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;JWT&lt;/span&gt;
&lt;span class="n"&gt;ALGORITHM&lt;/span&gt; &lt;span class="n"&gt;RS256&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;
&lt;span class="nv"&gt;"-----BEGIN PUBLIC KEY-----
MUO52Me9HEB4ZyU+7xmDpnixzA/CUE7kyUuE0b7t38oCh+sQouREqIjLwgHhFdhh3cQAwr6GH07D…."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enhanced security features
&lt;/h3&gt;

&lt;p&gt;From JWT and token-based authentication to new sanitation functions, 2.0 is designed with enterprise-grade security in mind. These features help safeguard your data against common vulnerabilities while offering the flexibility to integrate with third-party authentication providers, enabling a more  interconnected infrastructure.&lt;/p&gt;

&lt;p&gt;With SurrealDB 2.0 you now have a security framework that is both comprehensive and adaptable, ensuring that your data is protected in all scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  SDKs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Native types
&lt;/h3&gt;

&lt;p&gt;Across our JavaScript, C and Python SDKs, we've implemented powerful new handling for &lt;code&gt;strings&lt;/code&gt;, &lt;code&gt;numbers&lt;/code&gt;, &lt;code&gt;floats&lt;/code&gt;, and &lt;code&gt;booleans&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;JavaScript, .Net and PHP now leverage our brand-new CBOR protocol, while C and Python are now built on top of the Rust SDK, for even more efficient and accurate data processing. With custom datatypes like &lt;code&gt;Uuid&lt;/code&gt;, &lt;code&gt;RecordId&lt;/code&gt;, and &lt;code&gt;Geometry&lt;/code&gt; now supported, you can expect more versatile and efficient data handling, no matter which language you're working with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Type Safety
&lt;/h3&gt;

&lt;p&gt;We’re also committed to making our JavaScript SDK as type-safe and secure as possible. That’s why we’ve ensured out-of-the-box support for TypeScript! You can now enjoy seamless integrations with your favourite frameworks like React, SolidJS, and Vue, making your development process smoother and more efficient. PHP developers will be pleased to know that the same enhanced data handling is now at your fingertips, ensuring that your web applications benefit from the same cutting-edge technology.&lt;/p&gt;

&lt;h2&gt;
  
  
  SurrealML
&lt;/h2&gt;

&lt;p&gt;With SurrealML, you can now  seamlessly integrate machine learning into your workflows without changing your existing tech stack, enabling you to store, load, and execute models right next to your data, streamlining your processes and saving you valuable time.&lt;/p&gt;

&lt;p&gt;You can perform complex queries that compute columns based on calculations from the ML model, and then use these values to filter, group, or order your data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ml&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;house_price_prediction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="n"&gt;squarefoot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;squarefoot_col&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;num_floors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;num_floors_col&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;price_prediction&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;house_listing&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;price_prediction&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;177206&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;21875&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also have the ability to summarise statistics on these results with a single SQL query, keeping your insights up-to-date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="k"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price_prediction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="k"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price_prediction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price_prediction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price_prediction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;stddev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price_prediction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;stddev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;variance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price_prediction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;variance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;interquartile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price_prediction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;interquartile&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ml&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;house_price_prediction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="n"&gt;squarefoot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;squarefoot_col&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;num_floors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;num_floors_col&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;price_prediction&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;house_listing&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;squarefoot_col&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SurrealML specialises in seamlessly running your pre-trained models directly within your database, ensuring accurate and efficient data processing right where your data is stored. This allows data scientists and engineers to focus on driving smarter decisions and insights more easily and accurately.&lt;/p&gt;

&lt;h2&gt;
  
  
  SurrealKV
&lt;/h2&gt;

&lt;p&gt;We are excited to announce that in SurrealDB &lt;code&gt;2.0&lt;/code&gt;, we are now debuting our own native key value storage engine - SurrealKV. Built entirely in Rust - like the rest of SurrealDB - SurrealKV is an embedded ACID-compliant key-value storage engine with built-in versioning, that allows for historical or temporal querying.&lt;/p&gt;

&lt;h3&gt;
  
  
  Versioned querying
&lt;/h3&gt;

&lt;p&gt;SurrealKV enables immutable data querying, data change auditing, historic aggregate query analysis, and versioned queries across the graph.&lt;/p&gt;

&lt;p&gt;Currently, versioning is only possible when running on SurrealKV and you can access this using the &lt;code&gt;VERSION&lt;/code&gt; keyword and a &lt;code&gt;datetime&lt;/code&gt;. Here's an example to demonstrate how simple it is to view a snapshot of a table's records at any point in time.&lt;/p&gt;

&lt;p&gt;First, let's create the initial version of a record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;john&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'John v1'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's say that the current time is &lt;code&gt;2024-08-12 T11:30:00Z&lt;/code&gt;&lt;br&gt;
Now update the record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;john&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'John v2'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As expected, normal SELECT without a version returns the latest update&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt;
&lt;span class="p"&gt;[[{&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;john&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'John v2'&lt;/span&gt; &lt;span class="p"&gt;}]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the initial record, use the VERSION clause with the timestamp&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt; &lt;span class="k"&gt;VERSION&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="s1"&gt;'2024-08-12T11:03:00Z'&lt;/span&gt;
&lt;span class="p"&gt;[[{&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;john&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'John v1'&lt;/span&gt; &lt;span class="p"&gt;}]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ground-breaking query functionality, when combined with the advanced multi-model capabilities in SurrealDB, allows you to query data with an additional dimension, without sacrificing on performance, or forcing you to change your query in any other way. By enabling this functionality across records, record links, and graph edges, now you have the ability to time-travel across highly-connected graph data.&lt;/p&gt;

&lt;p&gt;Now that SurrealKV is a built-in option to SurrealDB, you can try it out too. To start a database instance with SurrealKV in SurrealDB 2.0, just add the surrealkv prefix and a file name to the &lt;a href="https://surrealdb.com/docs/surrealdb/cli/start#surrealkv-beta" rel="noopener noreferrer"&gt;&lt;code&gt;surreal start&lt;/code&gt;&lt;/a&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;surreal start surrealkv://my_database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;Building a database is never finished, when you think you’ve reached the summit, you instead see another summit to climb.&lt;/p&gt;

&lt;p&gt;The next summit we’re climbing leads into the &lt;a href="https://surrealdb.com/cloud" rel="noopener noreferrer"&gt;Surreal Cloud&lt;/a&gt;, which our cloud team has been moving heaven and earth to make happen, as you’ll see soon. &lt;/p&gt;

&lt;p&gt;Until then, we want to thank you for being on this journey with us!&lt;/p&gt;

</description>
      <category>database</category>
      <category>surrealdb</category>
    </item>
    <item>
      <title>Why SurrealDB is the Future of Database Technology - An In-Depth Look</title>
      <dc:creator>Alexander Fridriksson</dc:creator>
      <pubDate>Thu, 09 May 2024 15:09:03 +0000</pubDate>
      <link>https://dev.to/surrealdb/why-surrealdb-is-the-future-of-database-technology-an-in-depth-look-2jf9</link>
      <guid>https://dev.to/surrealdb/why-surrealdb-is-the-future-of-database-technology-an-in-depth-look-2jf9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Here's to the crazy ones, the misfits, the rebels, the troublemakers, the round pegs in the square holes... the ones who see things differently -- they're not fond of rules, and they have no respect for the status quo... You can quote them, disagree with them, glorify or vilify them, but the only thing you can't do is ignore them because they change things... They push the human race forward, and while some may see them as the crazy ones, we see genius, because the people who are crazy enough to think that they can change the world, are the ones who do. - &lt;a href="https://www.youtube.com/watch?v=5sMBhDv4sik"&gt;Apple, 1997&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The conventional wisdom would be to build upon an existing ecosystem, focusing on one thing and then gradually expanding your capabilities carefully over years or even decades.&lt;/p&gt;

&lt;p&gt;A crazy thing to do would be to create the ultimate multi-model database, or in simple terms, an "everything database" from scratch, all at once.&lt;/p&gt;

&lt;p&gt;The conventional wisdom would be to join a start-up accelerator in Silicon Valley and grow the team locally as a US-based company.&lt;/p&gt;

&lt;p&gt;A crazy thing to do would be to start a London-based but globally distributed company with your brother, and have your mother do the first screening of all your early employees.&lt;/p&gt;

&lt;p&gt;The conventional wisdom would be to choose black, blue or green as your brand colours.&lt;/p&gt;

&lt;p&gt;A crazy thing to do would be choosing pink and purple as your brand colours.&lt;/p&gt;

&lt;p&gt;The conventional wisdom would be to choose C or C++ for building your database.&lt;/p&gt;

&lt;p&gt;A crazy thing to do would be &lt;a href="https://surrealdb.com/blog/why-we-are-betting-on-rust/?utm_source=blog&amp;amp;utm_medium=post"&gt;betting on Rust&lt;/a&gt; for building your database.&lt;/p&gt;

&lt;p&gt;The conventional wisdom would be to hire top engineers from prestigious companies as your first employees.&lt;/p&gt;

&lt;p&gt;A crazy thing to do would be hiring an opera singer as your first employee and a &lt;a href="https://surrealdb.com/blog/maintainer-month-2023-behind-the-scenes-with-rushmore-mushambi/?utm_source=blog&amp;amp;utm_medium=post"&gt;founder with an accounting degree, based in Zimbabwe&lt;/a&gt; as your first engineering employee.&lt;/p&gt;

&lt;p&gt;As the results show, however, not being blinded by conventional wisdom has been vital in assembling our team of truly world-class rebel geniuses, pushing the boundaries of what databases (and database companies) can or even should do.&lt;/p&gt;

&lt;p&gt;Now that we've established that we are, by all accounts, "the crazy ones", let's dive into the change we want to see in the world and how we are pushing the database industry forward!&lt;/p&gt;

&lt;h2&gt;
  
  
  Ghosts of databases past
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;欲知未來 先察已然 / Study the Past if You Would Define the Future. - Confucius&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Ebenezer_Scrooge"&gt;Ebenezer Scrooge&lt;/a&gt; needed to understand his past and present to realise the painful future ahead of him unless he made significant changes. Just like Scrooge,  we need to understand a bit about the past and present of database decisions to realise why the changes we made in SurrealDB enable you to avoid a painful future as well.&lt;/p&gt;

&lt;p&gt;The most crucial thing to understand is that the developers of every database, old and new, are presented with a choice that has greater implications than any other.&lt;/p&gt;

&lt;p&gt;Which database, if any, are you going to be compatible with?&lt;/p&gt;

&lt;h3&gt;
  
  
  The Faustian bargain
&lt;/h3&gt;

&lt;p&gt;Unless the change you want to see in the world is simply to be the best hosting provider of a commodity database, that question quickly turns into a &lt;a href="https://www.britannica.com/topic/Faustian-bargain"&gt;Faustian bargain.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A Faustian bargain is a deal where you trade something of supreme importance such as your values or even your soul, in exchange for material benefits such as power or riches.&lt;/p&gt;

&lt;p&gt;For startups, the conventional wisdom says you should take this deal, which often means building upon or being compatible with a popular legacy database to more easily capture market share.&lt;/p&gt;

&lt;p&gt;This sounds reasonable, and at first it might make things easier, but that one decision will force you to make countless more and, perhaps without even realising it, you have now chained yourself to design decisions made in the previous century, decisions that made sense for a world that no longer exists.&lt;/p&gt;

&lt;p&gt;Not to mention that to be truly compatible, you need to be &lt;a href="https://www.techopedia.com/definition/18104/bug-compatible"&gt;bug-for-bug compatible&lt;/a&gt; which means you either have to introduce matching bugs in your code or spend a lot of your limited time fixing bugs in the legacy database at the expense of features in your new database.&lt;/p&gt;

&lt;p&gt;There is also the option of using marketing instead of engineering and claiming compatibility but with a lot of fine print:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We're legacy database compatible*** - trust me bro&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This also puts a ceiling on your innovation by constraining yourself to only incremental innovation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;legacy database, but faster&lt;/li&gt;
&lt;li&gt;legacy database, but distributed&lt;/li&gt;
&lt;li&gt;legacy database, but with better marketing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A classic &lt;a href="https://en.wikipedia.org/wiki/The_Innovator%27s_Dilemma"&gt;innovator's dilemma:&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I had asked people what they wanted, they would have said faster horses. - Henry Ford&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This type of innovation can certainly help you improve the world. However, only disruptive innovation, like Henry Ford's cars, can change the world and move us into the future.&lt;/p&gt;

&lt;p&gt;You might have started out with a grand vision, but through a series of reasonable compromises ended up &lt;a href="https://www.youtube.com/watch?v=lXO0ylemz68"&gt;same same, but different.&lt;/a&gt; An innovative square peg that forced itself through a cookie cutter to fit through the round hole.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man. - George Bernard Shaw&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Faustian bargains are therefore by their nature tragic or self-defeating for those who make them, because what is surrendered is ultimately far more valuable than what is obtained.&lt;/p&gt;

&lt;h3&gt;
  
  
  To build or not to build
&lt;/h3&gt;

&lt;p&gt;The second most important choice the developers of every database make is choosing which parts to build as your core product and which parts to rely on others for.&lt;/p&gt;

&lt;p&gt;The conventional wisdom here again is focusing on one key idea. This usually means being best-of-breed for one thing and integrating with other best-of-breed products. It may also mean integrating with an ecosystem of extensions for functionality outside this one key idea.&lt;/p&gt;

&lt;p&gt;This is also reasonable advice as it allows database developers to offload a lot of complexity to the end users.&lt;/p&gt;

&lt;p&gt;As an end user of a database however, this will come back to haunt you, unless you're making the simplest of CRUD applications.&lt;/p&gt;

&lt;p&gt;For most modern applications you now have to hunt down multiple databases, extensions or services and evaluate them to decide which ones are the best fit. They all come with their own limitations, various APIs and release cycles.&lt;/p&gt;

&lt;p&gt;Not to mention each needing approval from IT and dealing with different maintenance guarantees. Either you put your critical infrastructure into the hands of &lt;a href="https://www.explainxkcd.com/wiki/index.php/2347:_Dependency"&gt;a random person in Nebraska&lt;/a&gt; or you pay a premium for each best-of-breed database or extension, which often costs the same or more as your original database did because the other database or extension developers also need to make a living.&lt;/p&gt;

&lt;p&gt;Before you know it, you'll have abstractions upon abstractions, managing a microservice architecture made up of expensive managed services in a data merry-go-round of your best-of-breed databases and extensions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;complexity very, very bad. - &lt;a href="https://grugbrain.dev/#grug-on-complexity"&gt;Grug&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nobody plans an overly complex system, but as the eight-time entrepreneur-turned-educator Steve Blank famously said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No Plan Survives First Contact With Customers. - &lt;a href="https://steveblank.com/2010/04/08/no-plan-survives-first-contact-with-customers-%E2%80%93-business-plans-versus-business-models/"&gt;Steve Blank&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With all their requests, customers will force you into complexity, one way or another.&lt;br&gt;
This sets off a chain reaction resulting in databases being forced to abandon the idea of just doing one key thing and supporting more features, whether it makes sense to or not.&lt;/p&gt;

&lt;p&gt;As an example, &lt;a href="https://www.postgresql.org/docs/current/datatype-json.html"&gt;PostgreSQL was forced to add JSON support&lt;/a&gt; and &lt;a href="https://www.mongodb.com/docs/atlas/data-federation/query/query-with-sql/"&gt;MongoDB was forced to add SQL support&lt;/a&gt;. Giving rise to &lt;a href="https://tbtech.co/news/patchwork-systems-are-more-than-just-an-annoyance/"&gt;patchwork systems&lt;/a&gt;, which force new incompatible models on top of the old ones and call it a stack (don't forget to read the fine print).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Everyone has a plan until they get punched in the face. - Mike Tyson&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After being repeatedly punched in the face by the complex systems customers require you to build, you have three choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give up and go work on a farm&lt;/li&gt;
&lt;li&gt;Roll with the punches and learn to live with it&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://surrealdb.com/blog/dreaming-of-something-better/?utm_source=blog&amp;amp;utm_medium=post"&gt;Dream of something better&lt;/a&gt; and fight back against the complexity!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  A new hope
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;An elegant weapon for a more civilized age. - Obi-Wan Kenobi&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At a high level, SurrealDB aims to be an elegant weapon cutting through the complexity of traditional systems and &lt;a href="https://surrealdb.com/blog/eli5--why-surrealdb-explained-through-building-with-lego/?utm_source=blog&amp;amp;utm_medium=post"&gt;making building fun again!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our vision is to be the ultimate data platform for tomorrow’s technology by being the most powerful multi-model database platform and serverless cloud offering for developers, SMEs and enterprises.&lt;/p&gt;

&lt;p&gt;To achieve this vision, we have had to let go of conventional wisdom because:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We can't solve problems by using the same kind of thinking we used when we created them. - Albert Einstein&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But it’s not enough to think differently, we also need to execute differently!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want something new, you have to stop doing something old. - Peter Drucker&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is why we have been innovating across every layer of the database to bring you a data platform where features from document, graph, transactional, time-series, temporal, full-text search, vector search, machine learning and more all work seamlessly together, because it’s all one coherent system.&lt;/p&gt;
&lt;h3&gt;
  
  
  Storage layer innovation
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Separation of storage and compute
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkfjo5oq2izcl28mhnz3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkfjo5oq2izcl28mhnz3.jpg" alt="separation of storage and compute" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One key architectural decision was the separation of storage and compute.&lt;br&gt;
This has been a trend that started with analytical databases (OLAP) and which has since made its way into operational databases (OLTP).&lt;/p&gt;

&lt;p&gt;The key reason for separating storage and compute is so that you can scale your resources separately. This has several benefits such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Less wasted capacity as scale is optimised for each workload&lt;/li&gt;
&lt;li&gt;Greater cost efficiency&lt;/li&gt;
&lt;li&gt;Greater flexibility&lt;/li&gt;
&lt;li&gt;Better fault tolerance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we'll cover in more detail when we get to deployment, SurrealDB takes storage and compute separation to the next level by offering unparalleled deployment flexibility!&lt;/p&gt;
&lt;h4&gt;
  
  
  Creating a new data structure for our new key-value store
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fms6a9yxa4uizqo1z737a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fms6a9yxa4uizqo1z737a.jpg" alt="vart" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We currently use a &lt;a href="https://surrealdb.com/docs/surrealdb/introduction/architecture/?utm_source=blog&amp;amp;utm_medium=post"&gt;range of leading key-value stores&lt;/a&gt; depending on whether you're running SurrealDB embedded, single node, distributed, or directly in the browser. While they are all the best at what they do, we need them to do more!&lt;/p&gt;

&lt;p&gt;In order to achieve our mission of enabling the world to access data in the most powerful way, we need more powerful key-value stores!&lt;/p&gt;

&lt;p&gt;That is why we are building &lt;a href="https://github.com/surrealdb/surrealkv"&gt;SurrealKV&lt;/a&gt;, our own native ACID-compliant storage engine, written in Rust. SurrealKV will enable versioned queries over time, immutable data querying, data change auditing, historic aggregate query analysis, and versioned graph queries.&lt;/p&gt;

&lt;p&gt;This goes well beyond the simple time travel or temporal tables you might be familiar with. It enables SurrealDB to be a &lt;a href="https://en.wikipedia.org/wiki/Temporal_database"&gt;native temporal database&lt;/a&gt;, further extending our multi-model approach to cover Bitemporal modeling efficiently (optimised storage) and performantly (optimised compute) at the storage layer without all the complexity and effort of &lt;a href="https://www.abhinavomprakash.com/posts/understanding-bitemporal-data/"&gt;trying to do it yourself&lt;/a&gt; at the query layer.&lt;/p&gt;

&lt;p&gt;To achieve this we needed to design a new data structure, &lt;a href="https://surrealdb.com/blog/vart-a-persistent-data-structure-for-snapshot-isolation/?utm_source=blog&amp;amp;utm_medium=post"&gt;an Immutable Versioned Adaptive Radix Trie (VART)&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The term "&lt;strong&gt;Versioned&lt;/strong&gt;" in VART signifies the use of versioning, indicating a chronological record of every modification made to the tree.&lt;/p&gt;

&lt;p&gt;The "&lt;strong&gt;Adaptive&lt;/strong&gt;" attribute refers to the dynamic node sizes and the path compression technique, aimed at optimizing space utilization and enhancing overall performance.&lt;/p&gt;

&lt;p&gt;Lastly, the "&lt;strong&gt;Radix Trie&lt;/strong&gt;" component underscores the adoption of a tree-like data structure, specifically tailored for storing associative arrays. - &lt;a href="https://surrealdb.com/blog/vart-a-persistent-data-structure-for-snapshot-isolation/?utm_source=blog&amp;amp;utm_medium=post"&gt;Farhan Ali Khan&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our journey building SurrealKV is still in its early stages but moving at an unbelievably fast pace and we already have an &lt;a href="https://www.youtube.com/watch?v=kQQV2kDFHQA"&gt;experimental release.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you also want a more powerful key-value store, we'd love for you to &lt;a href="https://github.com/surrealdb/surrealkv"&gt;contribute, provide feedback, or report issues&lt;/a&gt; to help shape the future of SurrealKV!&lt;/p&gt;
&lt;h3&gt;
  
  
  Query layer innovation
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Record IDs
&lt;/h4&gt;

&lt;p&gt;It all starts with &lt;a href="https://surrealdb.com/blog/the-life-changing-magic-of-surrealdb-record-ids/?utm_source=blog&amp;amp;utm_medium=post"&gt;the life-changing magic of SurrealDB record IDs.&lt;/a&gt;&lt;br&gt;
A record ID has two parts, a table name and a record identifier, which looks like this &lt;code&gt;table:record&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The key innovation here is that when doing &lt;a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete"&gt;CRUD&lt;/a&gt; with a record ID, you don't have to do a table scan, it just directly fetches the record from the key-value store!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;the_future&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;m3laj0u0r5gb03d9b6rq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because it is directly fetching the record, it will always be fast, regardless of scale.&lt;/p&gt;

&lt;p&gt;Compared with having to rely on table scans, which get slower the more data you have.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;the_past&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;124316249&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This brings us to the second key point, introducing helpful default options that work well as you scale.&lt;/p&gt;

&lt;p&gt;Instead of the traditional default of auto-increment or serial IDs you might be used to from legacy databases, when you create a record in the future table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;the_future&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A random ID is assigned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;the_future&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;m3laj0u0r5gb03d9b6rq&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows you to avoid common scaling problems such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto incrementing that locks, impacting concurrency and scalability of your database.&lt;/li&gt;
&lt;li&gt;Accidental information disclosure through using IDs in URLs, giving away data size and velocity.&lt;/li&gt;
&lt;li&gt;Non-uniqueness across tables or table shards across distributed nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If sequential IDs are needed, we’d recommend you &lt;a href="https://surrealdb.com/docs/surrealdb/surrealql/functions/rand#randuuidv7/?utm_source=blog&amp;amp;utm_medium=post"&gt;use either a ulid or a uuid v7.&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;the_future&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ulid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;the_future&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;v7&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The integer as primary key defaults made sense for the world in which they were taken, the world before the internet, but they don't make sense anymore.&lt;/p&gt;

&lt;p&gt;By having helpful defaults we want to make it as easy as possible to &lt;a href="https://english.stackexchange.com/questions/77535/what-does-falling-into-the-pit-of-success-mean"&gt;fall into the pit of success:&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Pit of Success: in stark contrast to a summit, a peak, or a journey across a desert to find victory through many trials and surprises, we want our customers to simply fall into winning practices by using our platform and frameworks. To the extent that we make it easy to get into trouble we fail. - &lt;a href="https://english.stackexchange.com/questions/77535/what-does-falling-into-the-pit-of-success-mean"&gt;Rico Mariani&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Native multi-model
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxsw3me3ofz0dxi1a5mc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxsw3me3ofz0dxi1a5mc.jpg" alt="multi-model" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Earlier we talked about customers forcing complexity on you and databases needing to adapt by forcing new incompatible models on top of the old ones, JSON on top of SQL and SQL on top of JSON.&lt;/p&gt;

&lt;p&gt;The problem you end up with there is a great experience for the original data model but a second-class experience, or worse, for the other data models forced on top of it.&lt;br&gt;
You might need to learn a whole different query language for the different data models and have all sorts of limitations, which the original data model doesn't have.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://surrealdb.com/blog/what-are-multi-model-databases/?utm_source=blog&amp;amp;utm_medium=post"&gt;native multi-model database&lt;/a&gt; solves these problems by making all the data models (document, graph, relational, etc) the original data model and having one unified query language. In our case, the SQL-like query language SurrealQL, which comes with many quality-of-life improvements over other SQL dialects.&lt;/p&gt;

&lt;p&gt;For SurrealDB this means integrating the good parts of each data model seamlessly together.&lt;/p&gt;

&lt;p&gt;For example, being schemaless by default allows for rapid prototyping, which is a great thing about the document model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;free_future&lt;/span&gt; &lt;span class="n"&gt;CONTENT&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"Freedom!!"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As well as being fully ACID compliant and schemafull, which are great things about the relational model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;safe_future&lt;/span&gt; &lt;span class="n"&gt;SCHEMAFULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;FIELD&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;safe_future&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;safe_future&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;FIELD&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;safe_future&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;
&lt;span class="c1"&gt;-- lets also make sure the message is more then 1 letter&lt;/span&gt;
&lt;span class="n"&gt;ASSERT&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;safe_future&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'lock it down!'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or even something in between, a schemafull table with schemaless flexible fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;flexible_future&lt;/span&gt; &lt;span class="n"&gt;SCHEMAFULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;FIELD&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;flexible_future&lt;/span&gt; &lt;span class="n"&gt;FLEXIBLE&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;flexible_future&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"so meta!"&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;p&gt;When we were taking the decision of how to make relationships between our data, we decided to go &lt;a href="https://surrealdb.com/blog/beyond-sql-joins-exploring-surrealdbs-multi-model-relationships/?utm_source=blog&amp;amp;utm_medium=post"&gt;beyond SQL Joins&lt;/a&gt; and instead use &lt;a href="https://www.youtube.com/watch?v=TyX45cyZ-W0"&gt;document record links&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=zwQwKvMa9sU"&gt;graph relationships&lt;/a&gt; because establishing the relationships at write time makes it simpler and easier for everyone at query time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Using record links to select from the person and product table&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
&lt;span class="n"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;product_name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;review&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Using graph relations to select from the person and product table&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
&lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;person_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Real-time data sync
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygdfdf51b3lxc6v9fuc8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygdfdf51b3lxc6v9fuc8.jpg" alt="lq" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Streaming real-time transactional data is a difficult problem to solve, which is exactly why we made it extremely easy for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://surrealdb.com/products/realtime-data-sync/?utm_source=blog&amp;amp;utm_medium=post"&gt;Live Queries&lt;/a&gt; in SurrealDB enable a simple yet seamless way of building modern, responsive applications, whether connecting to SurrealDB as a traditional backend database, or when connecting directly to the database from the frontend.&lt;/p&gt;

&lt;p&gt;Live Queries give developers the ability to receive real-time change notifications to data as it is happening. Integrated directly within the table, row, and field level permissions of SurrealDB, each Live Query notification is unique and tailored to the authentication of the user who issued the query.&lt;/p&gt;

&lt;p&gt;Regardless of what a user has subscribed to, notifications will only be delivered based on the authenticated session of that user.&lt;/p&gt;

&lt;p&gt;To make a query like this one a Live Query...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;the_future&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...all it takes is one magic word to &lt;a href="https://surrealdb.com/blog/unlocking-streaming-data-magic-with-surrealdb-live-queries-and-change-feeds/?utm_source=blog&amp;amp;utm_medium=post"&gt;unlock streaming data magic&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;LIVE&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;the_future&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And by bringing the simplicity of Live Queries alongside the advanced nature of &lt;a href="https://surrealdb.com/docs/surrealdb/surrealql/statements/define/table#pre-computed-table-views/?utm_source=blog&amp;amp;utm_medium=post"&gt;pre-defined aggregate views&lt;/a&gt;, you can now build powerful dashboards that rely on aggregate data queries, computationally expensive analytics queries, and filtered collections of massive data sets - that update in real-time as your data in the database changes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Machine learning made easy
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffaio4mis5ezomw2f8hio.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffaio4mis5ezomw2f8hio.jpg" alt="ml" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://surrealdb.com/products/machine-learning/?utm_source=blog&amp;amp;utm_medium=post"&gt;SurrealML&lt;/a&gt; enables machine learning models to be greatly simplified, ensuring reproducibility and consistency in machine learning pipelines. Running on our Rust engine, models can be built in Python and imported into SurrealDB for inference within the database runtime.&lt;/p&gt;

&lt;p&gt;With support for model versioning, machine learning pipelines can be further simplified, bringing consistency and reproducibility to data normalisation and model inference, allowing for execution across multiple different Python versions, environments, and platforms.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://surrealdb.com/blog/what-is-surrealml-a-getting-started-guide/?utm_source=blog&amp;amp;utm_medium=post"&gt;It's easy to get started&lt;/a&gt; and once a model is uploaded to SurrealDB you can use it directly in SurrealQL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;ml&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;house&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;prediction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="n"&gt;squarefoot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;squarefoot_col&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;num_floors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;num_floors_col&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;price_prediction&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;house_listing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Indexing reimagined
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78tdzlnd6q8vxydk99c8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78tdzlnd6q8vxydk99c8.jpg" alt="ix" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SurrealDB has support for traditional &lt;a href="https://surrealdb.com/docs/surrealdb/surrealql/statements/define/indexes/?utm_source=blog&amp;amp;utm_medium=post"&gt;indexing&lt;/a&gt;, unique indexes and constraints, full-text search indexes, and vector-embedding indexing.&lt;/p&gt;

&lt;p&gt;We reimagined how indexing might be implemented - opting for a completely custom-built indexing engine, which sits within the SurrealDB core itself without the need for an additional external query language, or for indexing-specific functions or plugins.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;userEmailIndex&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt; &lt;span class="n"&gt;COLUMNS&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The indexing engine is agnostic to its deployment environment - whether running on top of IndexedDB in the browser, an embedded run-time in Rust or Python, or distributed over multiple nodes in a highly scalable cluster.&lt;/p&gt;

&lt;p&gt;Using the &lt;a href="https://surrealdb.com/docs/surrealdb/reference-guide/full-text-search/?utm_source=blog&amp;amp;utm_medium=post"&gt;full-text search&lt;/a&gt; indexing engine, SurrealDB allows developers to define custom analysers which specify exactly how their text data should be processed, with support for multiple tokenizers, advanced filters including Ngram, EdgeNGram, and Snowball, and support for 17 languages from English to Arabic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;userNameIndex&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt; &lt;span class="n"&gt;COLUMNS&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;SEARCH&lt;/span&gt; &lt;span class="n"&gt;ANALYZER&lt;/span&gt; &lt;span class="n"&gt;ascii&lt;/span&gt; &lt;span class="n"&gt;BM25&lt;/span&gt; &lt;span class="n"&gt;HIGHLIGHTS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;a href="https://surrealdb.com/docs/surrealdb/surrealql/statements/define/indexes#vector-search-indexes/?utm_source=blog&amp;amp;utm_medium=post"&gt;vector-embedding indexing&lt;/a&gt;, our initial implementation supports exact nearest neighbour retrieval for vectors of arbitrary size using Metric Trees, with support for HNSW-based approximate nearest neighbours retrieval coming soon.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;mt_pt&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;pts&lt;/span&gt; &lt;span class="n"&gt;FIELDS&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt; &lt;span class="n"&gt;MTREE&lt;/span&gt; &lt;span class="n"&gt;DIMENSION&lt;/span&gt; &lt;span class="mi"&gt;4&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://surrealdb.com/docs/surrealdb/surrealql/statements/define/indexes#m-tree-index/?utm_source=blog&amp;amp;utm_medium=post"&gt;In the example below&lt;/a&gt;, the query searches for points closest to the vector &lt;code&gt;[2,3,4,5]&lt;/code&gt; and uses &lt;a href="https://surrealdb.com/docs/surrealdb/surrealql/functions/vector/?utm_source=blog&amp;amp;utm_medium=post"&gt;vector functions&lt;/a&gt; to calculate the distance between two points, indicated by &lt;code&gt;&amp;lt;|2|&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;euclidean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pts&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deployment innovation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgac1f1hgyp7s45v7vga9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgac1f1hgyp7s45v7vga9.jpg" alt="deploy" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As mentioned above, SurrealDB takes storage and compute separation to the next level!&lt;/p&gt;

&lt;p&gt;Some companies have gone through the herculean effort of retrofitting a legacy database with decades of tech debt into a cloud-native solution with a custom storage backend, usually including some form of S3 object storage.&lt;/p&gt;

&lt;p&gt;Others have created a cloud-native database from scratch, which is compatible with a particular legacy database.&lt;/p&gt;

&lt;p&gt;What they all tend to have in common is that they are cloud-native, but also cloud-only because the architecture is custom-made with the cloud in mind.&lt;/p&gt;

&lt;p&gt;SurrealDB was designed from the start to have unparalleled deployment flexibility,&lt;br&gt;
combining the ease of use of embedded databases such as SQLite and the power of client-server databases with all our multi-model features into &lt;a href="https://github.com/surrealdb/surrealdb"&gt;a single Rust binary!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means you have access to all the features wherever you are running SurrealDB:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://surrealdb.com/docs/surrealdb/embedding/rust/?utm_source=blog&amp;amp;utm_medium=post"&gt;In embedded devices and IoT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://surrealdb.com/docs/surrealdb/installation/running/memory/?utm_source=blog&amp;amp;utm_medium=post"&gt;As a single-node, in-memory server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://surrealdb.com/docs/surrealdb/installation/running/file/?utm_source=blog&amp;amp;utm_medium=post"&gt;As a single-node, on-disk server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://surrealdb.com/docs/surrealdb/installation/running/tikv/?utm_source=blog&amp;amp;utm_medium=post"&gt;As a multi-node, scalable cluster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/surrealdb/surrealdb.wasm/?utm_source=blog&amp;amp;utm_medium=post"&gt;Embedded directly in the web browser using Web Assembly&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As seeing is believing, you can check out the same SurrealDB that runs distributed, running in Web Assembly and storing data to your browser right now &lt;a href="https://surrealist.app/"&gt;using our official management interface&lt;/a&gt;, you don't even have to log in!&lt;/p&gt;

&lt;p&gt;With unparalleled deployment flexibility, you naturally also need flexibility in how you connect to the database. That is why we offer &lt;a href="https://surrealdb.com/docs/surrealdb/integration/sdks/"&gt;SDKs for various languages&lt;/a&gt; such as Rust, JavaScript, Python, Golang, Java, and more!&lt;/p&gt;

&lt;p&gt;You can also connect directly to the database using our &lt;a href="https://surrealdb.com/docs/surrealdb/integration/http/?utm_source=blog&amp;amp;utm_medium=post"&gt;RESTful HTTP endpoints&lt;/a&gt; or our unified &lt;a href="https://surrealdb.com/docs/surrealdb/integration/rpc/?utm_source=blog&amp;amp;utm_medium=post"&gt;RPC protocol&lt;/a&gt;, supporting both WebSockets and using HTTP to &lt;code&gt;POST&lt;/code&gt; to the &lt;code&gt;/rpc&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stepping into the future
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You cannot predict the future, but you can create it. - Peter Drucker&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As we have seen, the change SurrealDB wants to see is to enable the world to access data in the most powerful way while simultaneously reducing your total system complexity, by offering a coherent data platform where everything works seamlessly together.&lt;/p&gt;

&lt;p&gt;Help us push the database industry forward by taking a step ahead into the future with us by signing up for the &lt;a href="https://surrealdb.com/cloud/?utm_source=blog&amp;amp;utm_medium=post"&gt;SurrealDB cloud waitlist&lt;/a&gt; or exploring &lt;a href="https://github.com/surrealdb/surrealdb"&gt;SurrealDB&lt;/a&gt; right in your browser using &lt;a href="https://surrealist.app/"&gt;Surrealist.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>surrealdb</category>
      <category>future</category>
      <category>devops</category>
    </item>
    <item>
      <title>Eli5 - Why SurrealDB, explained through building with LEGO</title>
      <dc:creator>Alexander Fridriksson</dc:creator>
      <pubDate>Mon, 15 Apr 2024 15:48:34 +0000</pubDate>
      <link>https://dev.to/surrealdb/eli5-why-surrealdb-explained-through-building-with-lego-2cna</link>
      <guid>https://dev.to/surrealdb/eli5-why-surrealdb-explained-through-building-with-lego-2cna</guid>
      <description>&lt;h2&gt;
  
  
  Can databases inspire a sense of child-like play?
&lt;/h2&gt;

&lt;p&gt;Some people might take offence at that question because of the belief that of course databases are supposed to be the pinnacle of boring technology #justusepostgres&lt;/p&gt;

&lt;p&gt;While we are all aware of the benefits of boring technology—nobody wants to be on call at 4 AM firefighting database downtime—what about the work you'll do 99% of the time?&lt;/p&gt;

&lt;p&gt;That's when there is an opportunity to make your life significantly less boring while getting more work done because &lt;a href="https://hbr.org/2022/05/why-work-should-be-fun"&gt;"work made fun gets done"&lt;/a&gt;, and what's more fun than child-like play?&lt;/p&gt;

&lt;p&gt;I therefore invite you to take off your "jaded adult" hat for a moment and channel that inner child energy. The energy you get from the love of building things, no roadmap, no managers, just pure building bliss!&lt;/p&gt;

&lt;p&gt;When you read that last sentence, what image did you have in mind?&lt;/p&gt;

&lt;p&gt;For me, when I'm picturing just pure building bliss, I'm immediately transported to my grandmother's living room as a child. I'm sitting on the floor with my friends, with random Lego bricks all around, and we're just putting that child-like imagination to full use making up stories and building as we go!&lt;/p&gt;

&lt;h2&gt;
  
  
  Then it happens!
&lt;/h2&gt;

&lt;p&gt;Our building goes from pure bliss to frustration and frantic searching... the random LEGO pieces stop fitting together... but the story must go on, so we search and search through the pile of random LEGO bricks all over the floor and... it's worse than we thought! We're missing some pieces we needed to complete our masterpiece!&lt;/p&gt;

&lt;p&gt;What do you think comes next?&lt;/p&gt;

&lt;p&gt;Of course, it's persuading the adults to buy more LEGO sets!&lt;/p&gt;

&lt;p&gt;This obviously doesn't always work, and even if it works it can take a lot of time to get the new set...&lt;/p&gt;

&lt;p&gt;Do we then just leave our masterpiece unfinished and do something else because the adults ruined everything... or do we accept their suggestion to “Just use what you have” and ruin it ourselves by forcing random pieces to fit together?&lt;/p&gt;

&lt;p&gt;As an adult that might not seem like a big deal, you don't have infinite money and your child has a lot of LEGO sets already. But as kids we're now upset, maybe even crying because the adults refused to let us get the LEGO sets which we obviously need!&lt;/p&gt;

&lt;h2&gt;
  
  
  When play becomes work
&lt;/h2&gt;

&lt;p&gt;Now you might be thinking, cool story bro, but what has this got to do with SurrealDB?&lt;/p&gt;

&lt;p&gt;Quite a lot, actually. See if you notice any similarities in the mindset we had as children with the one we have as adults working on databases.&lt;/p&gt;

&lt;p&gt;We started building full of excitement and made great progress until we realised we needed more LEGO sets to finish our masterpiece. After a lot of searching, we told the adults what we needed to complete our masterpiece and they told us no, use what you have, which left us with a difficult choice.&lt;/p&gt;

&lt;p&gt;We therefore learn that we often have to compromise our vision. We learn to be careful when we're starting something because we might end up disappointed. We learn to expect the adults to say no, so why even ask?&lt;/p&gt;

&lt;p&gt;But most of all, we learn that starting things is play but finishing things is work.&lt;/p&gt;

&lt;p&gt;Because at the start, we have all the LEGO pieces we need, and we can just be in builder mode, building as fast as we can think!&lt;/p&gt;

&lt;p&gt;...until the LEGO pieces run out or stop fitting together and we're now kicked out of builder mode and are forced into &lt;em&gt;compromise mode&lt;/em&gt;. We go from being full of excitement to being full of anxiety. Because our thoughts go from imagining what else we can build, to imagining what compromises we need to make and the potential conflicts that might cause.&lt;/p&gt;

&lt;p&gt;Play has now become work.&lt;/p&gt;

&lt;p&gt;But it doesn't have to be this way!&lt;/p&gt;

&lt;h2&gt;
  
  
  It's hard to compete with someone having fun
&lt;/h2&gt;

&lt;p&gt;At SurrealDB we're pushing the boundaries of what databases can or even should do, all so that you can spend as much time as possible having fun in the builder mode and as little time as possible in the anxiety-inducing &lt;em&gt;compromise mode&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We've looked at all the various LEGO sets that builders end up needing and created &lt;a href="https://www.lego.com/en-gb/aboutus/news/2023/february/lego-icons-the-lord-of-the-rings-rivendell"&gt;the one LEGO set to rule them all!&lt;/a&gt; ...or in other words, &lt;a href="https://surrealdb.com/?utm_source=blog&amp;amp;utm_medium=post"&gt;the ultimate multi-model database!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The one LEGO set makes it easy for you to start building and, more importantly, keep building without getting stuck searching for missing pieces, asking adults (managers) to buy more pieces or hoping all the random free pieces fit together. &lt;a href="https://www.youtube.com/watch?v=kHnn1XTnZCk"&gt;We've already made sure everything fits together so that you can have fun building!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This journey to remove as much friction as possible from the building process has resulted in a ton of technological innovation, which we'll cover more seriously in another blog post.&lt;/p&gt;

&lt;p&gt;The key message here is that work made fun gets done and we make databases fun to play around with!&lt;/p&gt;

&lt;p&gt;"Work made fun gets done" isn't just some meaningless slogan either, but backed up with science. As the &lt;a href="https://www.ted.com/talks/tom_wujec_build_a_tower_build_a_team"&gt;"marshmallow problem"&lt;/a&gt; demonstrates, kindergarten students having fun consistently outperformed well-educated adults in this well-known challenge to build a structure of dry spaghetti, one yard of tape and a marshmallow. It turns out that it's hard to compete with someone who is having fun!&lt;/p&gt;

&lt;p&gt;The key lesson from the challenge was about prototyping and iterating quickly, and what is prototyping if not playing around? There is a lot to be learned from child-like play!&lt;/p&gt;

&lt;p&gt;I would therefore encourage you to &lt;a href="https://www.youtube.com/watch?v=p2BXDus7yvc"&gt;play around with SurrealDB and have some fun!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>eli5</category>
      <category>surrealdb</category>
      <category>lego</category>
    </item>
    <item>
      <title>Why we are betting on Rust!</title>
      <dc:creator>Alexander Fridriksson</dc:creator>
      <pubDate>Wed, 13 Mar 2024 16:12:15 +0000</pubDate>
      <link>https://dev.to/surrealdb/why-we-are-betting-on-rust-4p7d</link>
      <guid>https://dev.to/surrealdb/why-we-are-betting-on-rust-4p7d</guid>
      <description>&lt;p&gt;SurrealDB has been built from the ground up to be the ultimate database for developers who want to build tomorrow's applications.&lt;/p&gt;

&lt;p&gt;In order to build the future of databases that can support the future of applications, we needed the future of low-level programming languages. We believe this language is Rust, which quite literally has allowed us to bring the &lt;a href="https://surrealdb.com/docs/surrealdb/surrealql/datamodel/futures/?utm_source=blog&amp;amp;utm_medium=post"&gt;&lt;code&gt;future&lt;/code&gt;&lt;/a&gt; to our SQL-like query language SurrealQL, inspired by the &lt;a href="https://doc.rust-lang.org/std/future/trait.Future.html"&gt;Rust future.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Go slow to go fast
&lt;/h2&gt;

&lt;p&gt;Front and centre on our home page, you'll see &lt;a href="https://surrealdb.com/?utm_source=blog&amp;amp;utm_medium=post"&gt;these three sentences&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Develop easier. &lt;/li&gt;
&lt;li&gt;Build faster. &lt;/li&gt;
&lt;li&gt;Scale quicker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not only what SurrealDB can do for your application, but what Rust does for SurrealDB. Due to Rust's notoriously steep learning curve, develop easier and build faster might not be the first thing that comes to mind when you think of using Rust.&lt;/p&gt;

&lt;p&gt;However, the ways Rust supports you to think differently, through using the borrow checker, lifetimes and more, pays compounding interest as your application starts achieving a phenomenal balance of safety and performance.&lt;/p&gt;

&lt;p&gt;Yes, you may not be as fast going from 0 to 1 in Rust as in some other languages, but &lt;a href="https://opensource.googleblog.com/2023/06/rust-fact-vs-fiction-5-insights-from-googles-rust-journey-2022.html"&gt;it's easier than you think.&lt;/a&gt; This might however mean prototyping in a different language and then re-writing it in Rust once you see a long-term potential for the project. &lt;a href="https://www.youtube.com/watch?v=Chl8IdMxr4Y"&gt;SurrealDB itself was first prototyped in Go and then entirely re-written in Rust.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key point here is that once you pay the upfront cost of learning Rust, you can go further faster, or as is often said: go slow to go fast.&lt;/p&gt;

&lt;p&gt;Now, before we go any further, we need to address the question I'm sure many of you will have: why not Zig or other newer languages?&lt;/p&gt;

&lt;p&gt;While it's true that you can build a database with Zig or other newer languages, they don't have the features of Rust when it comes to memory safety by default while not having a garbage collector for the highest performance. However, there is one thing that stands out more than any feature difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Critical adoption
&lt;/h2&gt;

&lt;p&gt;There is no denying that Rust has captured the hearts and minds of the developer community, having topped the chart as &lt;a href="https://survey.stackoverflow.co/2023/#section-admired-and-desired-programming-scripting-and-markup-languages"&gt;“the most admired programming language”&lt;/a&gt; in Stack Overflow’s annual developer survey for 8 years in a row. Far from being just admired, it's also one of the &lt;a href="https://octoverse.github.com/2022/top-programming-languages"&gt;fastest-growing languages on GitHub&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Rust has even achieved adoption where no other language aside from C has been, not even C++,  namely the &lt;a href="https://www.phoronix.com/news/Linux-6.6-Rust-Changes"&gt;Linux kernel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This begs the question, why?&lt;/p&gt;

&lt;p&gt;As &lt;a href="https://security.googleblog.com/2021/04/rust-in-linux-kernel.html"&gt;Software Engineer Wedson Almeida Filho said&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We feel that Rust is now ready to join C as a practical language for implementing the kernel. It can help us reduce the number of potential bugs and security vulnerabilities in privileged code while playing nicely with the core kernel and preserving its performance characteristics.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To put this into perspective, a talk at the &lt;a href="https://static.sched.com/hosted_files/lssna19/d6/kernel-modules-in-rust-lssna2019.pdf"&gt;2019 Linux Security Summit&lt;/a&gt; showed that memory safety issues are estimated to account for 65-88% of security vulnerabilities in major systems, including Android and Ubuntu. &lt;/p&gt;

&lt;p&gt;This also aligns with &lt;a href="https://msrc.microsoft.com/blog/2019/07/we-need-a-safer-systems-programming-language/"&gt;Microsoft's experience&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;~70% of the vulnerabilities Microsoft assigns a CVE each year continue to be memory safety issues&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This goes to show how even after decades of development from some of the best engineers using C and C++ best practices, issues such as accessing memory that has already been freed, data races, and other problems still persist. Therefore it's hard to claim it's just skill issues, but rather more likely fundamental issues with the languages being used. &lt;/p&gt;

&lt;p&gt;With this context in mind, you can see why &lt;a href="https://www.theregister.com/2022/09/20/rust_microsoft_c/"&gt;Microsoft Azure CTO Mark Russinovich said&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Speaking of languages, it's time to halt starting any new projects in C/C++ and use Rust for those scenarios where a non-GC language is required. For the sake of security and reliability. the industry should declare those languages as deprecated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This trust in Rust does not come from nowhere, there has been a tremendous amount of work put into making Rust fully usable in safety-critical environments. This can be seen in Rust's recent qualification under the ISO 26262 and IEC 61508 standards through the &lt;a href="https://ferrous-systems.com/blog/officially-qualified-ferrocene/"&gt;Ferrocene toolchain&lt;/a&gt; developed by Ferrous Systems.&lt;/p&gt;

&lt;p&gt;You might have also heard that governments are taking notice of these developments, such as the &lt;a href="https://www.whitehouse.gov/wp-content/uploads/2024/02/Final-ONCD-Technical-Report.pdf"&gt;US White House Office of the National Cyber Director (ONCD).&lt;/a&gt; This office issued a report last month (February 2024) recommending a move to memory-safe programming languages and pointing to Rust as an example of a potential replacement for C and C++ in safety-critical space systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's not rocket science
&lt;/h2&gt;

&lt;p&gt;While databases are not life-critical space systems, they often play a life-critical role in organisations. You want to keep your data safe and secure because if you lose your data, you can lose your business. &lt;/p&gt;

&lt;p&gt;Therefore if between 65-88% of security vulnerabilities in major systems can be caused by memory issues, it's not rocket science to understand why we are betting on Rust to keep your data as safe as possible.&lt;/p&gt;

&lt;p&gt;At SurrealDB we are passionate about building the future we want to see in the world. &lt;/p&gt;

&lt;p&gt;If you want to be a part of building this future, you can &lt;a href="http://surrealdb.com/careers/?utm_source=blog&amp;amp;utm_medium=post"&gt;join our exceptional team of Rust engineers&lt;/a&gt; and contribute to shaping the future of SurrealDB. &lt;/p&gt;

&lt;p&gt;If you want to be a part of experiencing this future, &lt;a href="https://surrealdb.com/docs/surrealdb/introduction/start/?utm_source=blog&amp;amp;utm_medium=post"&gt;get started with SurrealDB&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>database</category>
      <category>rust</category>
      <category>surrealdb</category>
    </item>
    <item>
      <title>Thinking Inside The Box: Relational Style Joins in SurrealDB</title>
      <dc:creator>Alexander Fridriksson</dc:creator>
      <pubDate>Wed, 21 Feb 2024 16:23:07 +0000</pubDate>
      <link>https://dev.to/surrealdb/thinking-inside-the-box-relational-style-joins-in-surrealdb-4a9a</link>
      <guid>https://dev.to/surrealdb/thinking-inside-the-box-relational-style-joins-in-surrealdb-4a9a</guid>
      <description>&lt;p&gt;SurrealDB doesn't do traditional SQL joins. What we have instead done is think from first principles what developers need from database relationships to be able to develop easier and scale quicker.&lt;/p&gt;

&lt;p&gt;This led us to our primary ways of creating relationships at write time to simplify scaling and improve developer experience at query time. To dig more into that, see our previous &lt;a href="https://surrealdb.com/blog/beyond-sql-joins-exploring-surrealdbs-multi-model-relationships"&gt;Beyond SQL Joins&lt;/a&gt; blog post.&lt;/p&gt;

&lt;p&gt;That blog post ended with the question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;However, what if we want to make arbitrary relationships on the fly similar to relational style joins?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's now explore the answer to that question where, spoiler alert, we will learn about semi-joins, anti-joins, and correlated subqueries. Those are fancy terms, but don't worry, it's all going to make sense soon enough 😉&lt;/p&gt;

&lt;p&gt;Starting with:&lt;/p&gt;

&lt;h2&gt;
  
  
  It's me, subquery, I'm the problem, It's me
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4w0ul6zn532929dgeu01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4w0ul6zn532929dgeu01.png" alt="wait its all subqueries, always has been" width="479" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that the secret is out of the bag, let's dive into the code to show how it works in practice.&lt;/p&gt;

&lt;p&gt;Our data and examples for today will be based on the &lt;a href="https://www.w3schools.com/sql"&gt;w3schools SQL tutorial&lt;/a&gt;(great resource btw) where we will compare the SQL approach shown there with SurrealQL.&lt;/p&gt;

&lt;p&gt;This is the very simple schema that we will be using, consisting of a product table and a supplier table.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
    &lt;tr&gt;
&lt;th&gt;ProductID&lt;/th&gt;
&lt;th&gt;ProductName&lt;/th&gt;
&lt;th&gt;SupplierID&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
    &lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Chais&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;/tr&gt;
    &lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Chang&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;/tr&gt;
    &lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Aniseed Syrup&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
    &lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Chef Anton's Cajun Seasoning&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;/tr&gt;
    &lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Chef Anton's Gumbo Mix&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;21.35&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
    &lt;tr&gt;
&lt;th&gt;SupplierID&lt;/th&gt;
&lt;th&gt;SupplierName&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
    &lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Exotic Liquid&lt;/td&gt;
&lt;/tr&gt;
    &lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;New Orleans Cajun Delights&lt;/td&gt;
&lt;/tr&gt;
    &lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Grandma Kelly's Homestead&lt;/td&gt;
&lt;/tr&gt;
    &lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Tokyo Traders&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you want to follow along, you can go to &lt;a href="https://surrealist.app/"&gt;https://surrealist.app/&lt;/a&gt;&lt;br&gt;
→ Create session&lt;br&gt;
→ Click on sandbox&lt;br&gt;
→ Type any name for namespace and database&lt;br&gt;
→ Copy and paste the two queries below, which work both for SurrealDB and most relational DBs&lt;/p&gt;

&lt;p&gt;Products table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProductID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ProductName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SupplierID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"Chais"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"Chang"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"Aniseed Syrup"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"Chef Anton's Cajun Seasoning"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"Chef Anton's Gumbo Mix"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Supplier table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;Suppliers&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SupplierID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SupplierName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"Exotic Liquid"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"New Orleans Cajun Delights"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"Grandma Kelly's Homestead"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"Tokyo Traders"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Semi-Joins
&lt;/h2&gt;

&lt;p&gt;It's a subquery that filters the outer query with the results of the inner query. &lt;/p&gt;

&lt;p&gt;Now that we've got the dictionary definition out of the way, let's get to the exciting stuff, where we'll explore the same query written in 3 different ways in both SQL and SurrealQL. &lt;/p&gt;

&lt;p&gt;This will really help you see the difference between a semi-join, correlated subquery and a traditional SQL join.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;IN&lt;/code&gt; example
&lt;/h3&gt;

&lt;p&gt;As SurrealQL is a SQL-like language, you’ll notice that the examples will look very similar, such as just a single word difference like in the below example, see if you can spot it.&lt;/p&gt;

&lt;h4&gt;
  
  
  SQL Example
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Outer query&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;SupplierName&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Suppliers&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;SupplierID&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;-- Inner query&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;SupplierID&lt;/span&gt; 
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt; 
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  SurrealQL Example
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Outer query&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;SupplierName&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Suppliers&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;SupplierID&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;-- Inner query&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;SupplierID&lt;/span&gt; 
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt; 
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since inner queries run before outer queries, it's often good to read subqueries from the inside out.&lt;/p&gt;

&lt;p&gt;Starting with us filtering for products in the &lt;code&gt;Products&lt;/code&gt; table that have a price less than 20, then "joining" the &lt;code&gt;Products&lt;/code&gt; table to the &lt;code&gt;Suppliers&lt;/code&gt; table using the &lt;code&gt;SupplierID&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This then allows us to see the names of the suppliers which have products where the price is less than 20.&lt;/p&gt;

&lt;p&gt;The reason why you see the word &lt;code&gt;VALUE&lt;/code&gt; added to the &lt;code&gt;SELECT&lt;/code&gt; in SurreaQL is because by default SurrealDB returns objects. Since we want to check if an ID is in an array of IDs, &lt;a href="https://docs.surrealdb.com/docs/surrealql/statements/select#basic-usage"&gt;&lt;code&gt;SELECT VALUE&lt;/code&gt;&lt;/a&gt; allows you to return an array of values instead.&lt;/p&gt;

&lt;p&gt;A key thing to notice here is that the entirety of the inner query is run before the outer query, which would make it an uncorrelated subquery. This does have some pros and cons, as we'll explore in our next example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Correlated subquery example
&lt;/h3&gt;

&lt;p&gt;It's still a subquery that filters the outer query with the results of the inner query and is a type of semi-join.&lt;/p&gt;

&lt;h4&gt;
  
  
  SQL example
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;SupplierName&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Suppliers&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;SupplierID&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt; 
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SupplierID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Suppliers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;supplierID&lt;/span&gt; 
    &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
    &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SurrealQL example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;SupplierName&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Suppliers&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;SupplierID&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;SupplierID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SupplierID&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
    &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key difference here is that the inner query can't run without the outer query, as you can see in the &lt;code&gt;WHERE&lt;/code&gt; statement. Where the defining characteristic of correlated subqueries is that it references a column in the outer query and executes the subquery once for each row in the outer query.&lt;/p&gt;

&lt;p&gt;Now you might be wondering, why would we do that?&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhif93fxc0mtx28vs3zh8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhif93fxc0mtx28vs3zh8.png" alt="Why cat" width="486" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a straightforward answer to that: it might be more performant, but as always, it depends™&lt;/p&gt;

&lt;p&gt;One of the things it depends on is how your query optimiser treats it, but it also depends on how large the table of the inner query is and how complicated the logic is.&lt;/p&gt;

&lt;p&gt;In our example, the product table is small and only filters on price, so it's not a big deal to scan the whole table. The reason why &lt;code&gt;WHERE SupplierID = $parent.SupplierID&lt;/code&gt; can be more performant is because we are limiting the range of possible records/rows to scan to only those relevant to the outer query. In addition we are also adding &lt;code&gt;LIMIT 1&lt;/code&gt; to the inner query since we are executing the subquery once for each row in the outer query, therefore we can further reduce the rows returned by the inner query.&lt;/p&gt;

&lt;p&gt;There are also reasons to do it that are not directly related to performance, such as you could literally run out of memory if the product table were large enough... which we won't cover here so that you won't run out of memory for this blog post 😉&lt;/p&gt;

&lt;p&gt;The key thing to remember is that you cannot assume one way is always better as it depends on the above factors and more. Therefore its worth testing both if you need the best performance as the results might surprise you.&lt;/p&gt;
&lt;h2&gt;
  
  
  Anti-Joins
&lt;/h2&gt;

&lt;p&gt;You're in for a surprise here... nah, just kidding, It's still a subquery that filters the outer query with the results of the inner query.&lt;/p&gt;

&lt;p&gt;The only difference is that it's the opposite of the queries above. Instead of &lt;code&gt;IN&lt;/code&gt;, it is &lt;code&gt;NOT IN&lt;/code&gt;, and instead of &lt;code&gt;EXISTS&lt;/code&gt;, it's &lt;code&gt;NOT EXISTS&lt;/code&gt;. However since SurrealDB doesn’t use &lt;code&gt;EXIST&lt;/code&gt; you instead put &lt;code&gt;!&lt;/code&gt; in front of the subquery, to indicate &lt;code&gt;NOT EXISTS&lt;/code&gt; like in this SurrealQL example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;SupplierName&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Suppliers&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;SupplierID&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;SupplierID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SupplierID&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
    &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SQL join example
&lt;/h3&gt;

&lt;p&gt;Ok ok, enough with the subqueries, let's look at how this compares to a normal SQL join. &lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;LEFT JOIN&lt;/code&gt; example
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;DISTINCT&lt;/span&gt; &lt;span class="n"&gt;Suppliers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SupplierName&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Suppliers&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SupplierID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Suppliers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;supplierID&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just to reiterate, the &lt;code&gt;IN&lt;/code&gt;, &lt;code&gt;EXIST&lt;/code&gt;, and this &lt;code&gt;LEFT JOIN&lt;/code&gt; examples all give the same results, they just have a different way of getting there.&lt;/p&gt;

&lt;p&gt;This &lt;code&gt;LEFT JOIN&lt;/code&gt; approach would probably be most people's initial approach, but can you spot why it might be better to use the subquery approach as seen above?&lt;/p&gt;

&lt;p&gt;It's because with the &lt;code&gt;LEFT JOIN&lt;/code&gt; we get duplicate results that we then need to de-duplicate. This might be less performant than the subqueries, but again, it depends™&lt;/p&gt;

&lt;p&gt;SurrealDB does not do these typical joins and one of the reasons is this unnecessary computation of getting more data than you need and then spending even more computing resources on de-duplicating/filtering the data back down to what you actually need. &lt;/p&gt;

&lt;p&gt;But that leaves the question, how would you do it instead in SurrealDB?&lt;/p&gt;

&lt;p&gt;One possibility is using record links:&lt;/p&gt;

&lt;h3&gt;
  
  
  SurrealQL record links example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="n"&gt;Suppliers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SupplierName&lt;/span&gt;  
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see in this example, things don't need to be complicated. &lt;/p&gt;

&lt;p&gt;This example will produce the same result as the semi-joins and the left join, but without any table scan at all due to &lt;a href="https://surrealdb.com/blog/the-life-changing-magic-of-surrealdb-record-ids"&gt;how our record IDs work.&lt;/a&gt;(if you're following along, this query will not work with the imported dataset, because that is using SQL numeric IDs instead of SurrealDB record IDs).&lt;/p&gt;

&lt;p&gt;If you can make relationships at write time, you can have peace of mind at query time that you're not going to get duplicate data that you then need to remember to de-duplicate. That is even if everyone who has access to this can remember to use the right join conditions to begin with 😅&lt;/p&gt;

&lt;p&gt;I hope this clears some of the fears of missing out (FOMO) that you might have about SurrealDB not having traditional SQL joins. You can still do the things you need to do such as with the subqueries. When it comes to the traditional joins though, we think about it more in terms of the joy of missing out (JOMO) because the best way to reduce errors in your code is by &lt;a href="https://github.com/kelseyhightower/nocode"&gt;writing less code&lt;/a&gt;, as seen in our record links example.&lt;/p&gt;

&lt;p&gt;If this has piqued your interest, why not check out our previous &lt;a href="https://surrealdb.com/blog/beyond-sql-joins-exploring-surrealdbs-multi-model-relationships"&gt;Beyond SQL Joins&lt;/a&gt; blog post or just &lt;a href="https://docs.surrealdb.com/docs/installation/overview/"&gt;get started with SurrealDB&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>surrealql</category>
      <category>database</category>
    </item>
    <item>
      <title>Faster horses and flying cars</title>
      <dc:creator>Alexander Fridriksson</dc:creator>
      <pubDate>Mon, 07 Aug 2023 14:14:01 +0000</pubDate>
      <link>https://dev.to/datastorydesign/faster-horses-and-flying-cars-13gn</link>
      <guid>https://dev.to/datastorydesign/faster-horses-and-flying-cars-13gn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;If I had asked people what they wanted, they would have said faster horses. - Henry Ford&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most people didn’t see the need for a car when everything depended on horses. &lt;/p&gt;

&lt;p&gt;I’m sure Henry Ford heard a lot of this back in his day:&lt;/p&gt;

&lt;p&gt;“ Why are you spending so much time on this useless car idea, cars will never become as reliable as horses. Just stick to what works, you don’t have to reinvent the wheel! “&lt;/p&gt;

&lt;p&gt;Now we all know that Henry Ford did not give up and, for all intents and purposes, did reinvent the wheel in terms of changing how the world does transportation.&lt;/p&gt;

&lt;p&gt;Now my question is: why don’t we have flying cars?&lt;/p&gt;

&lt;p&gt;Have we, just like our ancestors, settled for faster cars instead of taking the next step into the future of transportation?&lt;/p&gt;

&lt;p&gt;Let’s bring this home to us, SurrealDB is a database company, not a car maker. However, there are plenty of similarities between our vision for the future of databases and Henry Ford’s vision for the future of transportation.&lt;/p&gt;

&lt;p&gt;In our case, Henry’s famous quote would say &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I would have asked people what they wanted, they would have said a faster Postgres&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Right? &lt;/p&gt;

&lt;p&gt;It certainly feels like that at times:&lt;/p&gt;

&lt;p&gt;“ Why are you spending so much time on this useless database idea, SurrealDB will never become as reliable as Postgres. Just stick to what works, you don’t have to reinvent the wheel! “&lt;/p&gt;

&lt;p&gt;Therefore the question is, will we give up?&lt;br&gt;
This question is on the minds of a lot of people that want to adopt our technology.&lt;/p&gt;

&lt;p&gt;And I’m here to assure you that the answer is no, we will not give up!&lt;/p&gt;

&lt;p&gt;Why am I so sure of this? &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The people who are crazy enough to think they can change the world are the ones that do. - Steve Jobs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This company is made up of people who have overcome a lot to get where we are today therefore, we know we can make a change and are not afraid to overcome the challenges ahead!&lt;/p&gt;

&lt;p&gt;We are daring to reinvent the wheel and take the next step into the future of databases. &lt;/p&gt;

&lt;p&gt;If you want to join us, then I encourage you to sign up for our &lt;a href="https://surrealdb.world/"&gt;version 1.0 launch event on September 13&lt;/a&gt; to see what the future holds! &lt;/p&gt;

&lt;p&gt;And, of course, join us on &lt;a href="https://surrealdb.com/discord"&gt;Discord&lt;/a&gt;, we’d love to hear from you!&lt;/p&gt;

</description>
      <category>innovation</category>
      <category>database</category>
    </item>
    <item>
      <title>The life-changing magic of SurrealDB - record IDs</title>
      <dc:creator>Alexander Fridriksson</dc:creator>
      <pubDate>Thu, 11 May 2023 15:25:54 +0000</pubDate>
      <link>https://dev.to/surrealdb/the-life-changing-magic-of-surrealdb-record-ids-58li</link>
      <guid>https://dev.to/surrealdb/the-life-changing-magic-of-surrealdb-record-ids-58li</guid>
      <description>&lt;p&gt;At SurrealDB, we are all about doing things that spark joy for developers ✨&lt;br&gt;
One of those things that constantly surprises and delights is the humble record ID, which we discussed in &lt;a href="https://www.youtube.com/watch?v=c0cqmWRYP8c" rel="noopener noreferrer"&gt;our live stream&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Far from being just a boring number, your queries can be magical. &lt;/p&gt;

&lt;p&gt;Without further ado, then, let's learn some surreal magic! ✨&lt;/p&gt;
&lt;h2&gt;
  
  
  The look and feel
&lt;/h2&gt;

&lt;p&gt;The first thing to be aware of is that in SurrealDB, a record ID has two parts, a table name and a record identifier, which looks like this &lt;code&gt;table:record&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By default, when you create a table, &lt;code&gt;create internet&lt;/code&gt;, a random id is assigned. This differs from the traditional default of auto-increment or serial IDs you might be used to.&lt;/p&gt;

&lt;p&gt;This allows you to avoid common problems such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Impact on the concurrency and scalability of your database.&lt;/li&gt;
&lt;li&gt;Accidental information disclosure through using IDs in URLs, giving away data size and velocity.&lt;/li&gt;
&lt;li&gt;Non-uniqueness across tables or table shards across distributed nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The typical solution to this is to use cryptographically secure randomly generated identifiers such as our default &lt;code&gt;rand()&lt;/code&gt;, but you can also use &lt;code&gt;ulid()&lt;/code&gt; and &lt;code&gt;uuid()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In a nutshell, we want to make it as easy as possible to &lt;a href="https://english.stackexchange.com/questions/77535/what-does-falling-into-the-pit-of-success-mean" rel="noopener noreferrer"&gt;fall into the pit of success&lt;/a&gt;, where the default option works well as you scale.&lt;/p&gt;

&lt;p&gt;Let's step back a bit and look at the simplest example of comparing SQL and SurrealQL, where we select one id from a table.&lt;/p&gt;

&lt;p&gt;SQL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;internet&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1337&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just a completely run-of-the-mill example, nothing special about it.&lt;/p&gt;

&lt;p&gt;SurrealQL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;internet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;leet&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we can see something new. We can filter to a record right from the from statement!&lt;/p&gt;

&lt;p&gt;This would be the shorthand example for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;internet&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;internet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;leet&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's step it up a bit. What if we needed to select a range of ids?&lt;/p&gt;

&lt;p&gt;SQL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Over 9000!&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;internet&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;9000&lt;/span&gt;

&lt;span class="c1"&gt;-- less than 9000&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;internet&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;9000&lt;/span&gt;

&lt;span class="c1"&gt;-- between 9000 and 10000&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;internet&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;9000&lt;/span&gt;
&lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SurrealQL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Over 9000!&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;internet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;

&lt;span class="c1"&gt;-- less than 9000&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;internet&lt;/span&gt;&lt;span class="p"&gt;:..&lt;/span&gt;&lt;span class="mi"&gt;9000&lt;/span&gt;

&lt;span class="c1"&gt;-- between 9000 and 10000&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;internet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, this is much more than just some syntactic sugar!&lt;/p&gt;

&lt;p&gt;To understand why, we need to talk a bit about algorithmic complexity... don't worry. It's not that complicated 😉&lt;/p&gt;

&lt;h2&gt;
  
  
  The performance at scale
&lt;/h2&gt;

&lt;p&gt;In the simplest of terms, an algorithm is just a recipe for a sequence of steps (do this, then that). Therefore, algorithmic complexity (often talked about in terms of &lt;a href="https://en.wikipedia.org/wiki/Big_O_notation" rel="noopener noreferrer"&gt;asymptotic/big O notation&lt;/a&gt;) is just a way to estimate how many steps are likely to be in the sequence. The fewer steps the better.&lt;/p&gt;

&lt;p&gt;With SurrealQL, when doing &lt;a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete" rel="noopener noreferrer"&gt;CRUD&lt;/a&gt; with a record ID, you don't have to do a table scan, which gets slower the more data you have. This is because the algorithm most databases use for this is &lt;code&gt;O(log n)&lt;/code&gt; instead of the &lt;code&gt;O(1)&lt;/code&gt; key-value lookup in SurrealDB, which has near-constant performance regardless of scale. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fzbwh1vxzpnqgvara4fkw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fzbwh1vxzpnqgvara4fkw.jpeg" alt="big-o"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This makes working with IDs extremely fast as you scale and opens up new use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  The flexibility
&lt;/h2&gt;

&lt;p&gt;Now it's time for some real magic ✨&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fujpdbcdxhsrdufbjbq86.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fujpdbcdxhsrdufbjbq86.jpeg" alt="morpheus-free-your-mind"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's time to &lt;a href="https://youtu.be/ef_agVIvh0A?t=4" rel="noopener noreferrer"&gt;free your mind&lt;/a&gt; and rethink what is possible with an ID.&lt;/p&gt;

&lt;p&gt;SurrealDB's Complex Record IDs support dynamic expressions, allowing parameters and function expressions to be used as values within the IDs!&lt;/p&gt;

&lt;p&gt;This is useful in various ways, such as a time series context or ensuring locality between specific records in a table. Effectively creating clustered indexes &amp;amp; partitions naturally in your data as you scale with the performance of the ID lookup regardless of size!&lt;/p&gt;

&lt;p&gt;While this does not replace traditional indexes or partitions for your data, it offers additional flexibility to model the data in a performant way. &lt;/p&gt;

&lt;p&gt;Let's look at an example of creating Object-based Record IDs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Set a new parameter&lt;/span&gt;
&lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;-- Create a record with a complex ID using an object&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt; &lt;span class="k"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'London'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt;
    &lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'London'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;
&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also create Array-based Record IDs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Set a new parameter&lt;/span&gt;
&lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;-- Create a record with a complex ID using an array&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s1"&gt;'London'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt;
    &lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'London'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;
&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which you can query like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Select all records for a particular location, inclusive&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s1"&gt;'London'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NONE&lt;/span&gt;&lt;span class="p"&gt;]..&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'London'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()];&lt;/span&gt;

&lt;span class="c1"&gt;-- Select all temperature records with IDs between the specified range&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s1"&gt;'London'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2022-08-29T08:03:39'&lt;/span&gt;&lt;span class="p"&gt;]..[&lt;/span&gt;&lt;span class="s1"&gt;'London'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2022-08-29T08:09:31'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, pretty much the only limit to what a record ID can be is &lt;a href="https://www.youtube.com/watch?v=uAXtO5dMqEI" rel="noopener noreferrer"&gt;your imagination&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The future
&lt;/h2&gt;

&lt;p&gt;We have just scratched the surface of what you can do with record IDs. If you want to dig deeper, take a look at &lt;a href="https://www.youtube.com/watch?v=c0cqmWRYP8c" rel="noopener noreferrer"&gt;our stream about Record IDs&lt;/a&gt;, featuring even more powerful capabilities, or check out &lt;a href="https://surrealdb.com/docs/surrealql/datamodel/ids" rel="noopener noreferrer"&gt;our documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If this has sparked some ideas, perhaps something you've always wanted was possible, we'd love to hear from you!&lt;/p&gt;

&lt;p&gt;You'll find us at all the usual places, including our &lt;a href="https://discord.gg/surrealdb" rel="noopener noreferrer"&gt;discord&lt;/a&gt; and &lt;a href="https://github.com/surrealdb/surrealdb" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>data</category>
      <category>database</category>
      <category>surrealdb</category>
    </item>
    <item>
      <title>The ultimate beginners guide to databases</title>
      <dc:creator>Alexander Fridriksson</dc:creator>
      <pubDate>Fri, 21 Apr 2023 11:20:34 +0000</pubDate>
      <link>https://dev.to/surrealdb/the-ultimate-beginners-guide-to-databases-4g2a</link>
      <guid>https://dev.to/surrealdb/the-ultimate-beginners-guide-to-databases-4g2a</guid>
      <description>&lt;p&gt;What is a database, and why do we need one?&lt;/p&gt;

&lt;p&gt;Better yet, why do companies keep creating new databases since we already have over 300 of them?&lt;/p&gt;

&lt;p&gt;If you are curious about those questions, you have come to the right place.&lt;/p&gt;

&lt;p&gt;We will strip away all the fancy jargon and technical details and focus on understanding the essential concepts of databases through simple analogies.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do we make sense of the word?
&lt;/h2&gt;

&lt;p&gt;As long as humans have existed on this planet, we have tried to make sense of it.&lt;br&gt;
Just as cavemen drew symbols on walls, we draw symbols on paper... or perhaps more accurately... we type emojis into our smartphones.&lt;/p&gt;

&lt;p&gt;Regardless of how we do it, it's always about storing and sharing information in some form.&lt;/p&gt;

&lt;p&gt;That, in its essence, is what databases do, store and share information.&lt;/p&gt;

&lt;p&gt;We have gotten a lot better at storing and sharing information over the years, from cave walls to the printing press and many things in between.&lt;/p&gt;

&lt;p&gt;However, something fundamentally changed when computers arrived. We transitioned from storing and sharing information physically to storing and sharing information digitally.&lt;/p&gt;

&lt;h2&gt;
  
  
  From pen and paper to CRUD with digital paper
&lt;/h2&gt;

&lt;p&gt;Instead of just using paper to store and share information, we now had access to digital paper: databases.&lt;/p&gt;

&lt;p&gt;We couldn't interact with this digital world physically. Instead, we had to tell the computer how to interact with it on our behalf. This required new mental models and new languages. &lt;/p&gt;

&lt;p&gt;The most fundamental mental model is CRUD, &lt;a href="https://archive.org/details/managingdatabase00mart/page/380/mode/2up"&gt;a term coined in 1983&lt;/a&gt;, which stands for Create, Read, Update and Delete.&lt;/p&gt;

&lt;p&gt;Those are the four fundamental ways we interact with data of any kind, anywhere.&lt;/p&gt;

&lt;p&gt;Put simply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create = make data / let's write a poem on a piece of paper.&lt;/li&gt;
&lt;li&gt;Read = retrieve data / find the piece of paper you wrote on and read the poem.&lt;/li&gt;
&lt;li&gt;Update = change data / let's change a few lines in the poem.&lt;/li&gt;
&lt;li&gt;Delete = remove data / the poem wasn't good, let's throw the paper in the trash bin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While databases trace their origin back to the 1960s with the &lt;a href="https://en.wikipedia.org/wiki/Integrated_Data_Store"&gt;Integrated Data Store (IDS)&lt;/a&gt;, databases, as we know them today, got started in the 1970s.&lt;/p&gt;

&lt;p&gt;In June of 1970, it's fair to say that Edgar F. Codd made a dent in the universe with his paper titled &lt;a href="http://www.morganslibrary.net/files/codd-1970.pdf"&gt;A Relational Model of Data for Large Shared Data Banks&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;That paper gave rise to most of the concepts we still use today in relational databases, which we will explore soon.&lt;/p&gt;

&lt;p&gt;The most notable thing missing from his paper was how to put these genius ideas into practice, since most people (myself included) are not set theory geniuses.&lt;/p&gt;

&lt;p&gt;It wasn't until a few years later that Donald D. Chamberlin and Raymond Boyce, after reading Codd's paper, came up with another genius breakthrough. A new language for making practical use of the relational model ideas. They called it Structured English Query Language or &lt;a href="https://en.wikipedia.org/wiki/SQL"&gt;SEQUEL&lt;/a&gt; for short. &lt;/p&gt;

&lt;p&gt;Genius researchers can apparently also be somewhat petty, where part of the reason it was called SEQUEL was to tease other researchers who made the &lt;a href="https://en.wikipedia.org/wiki/QUEL_query_languages"&gt;QUEL&lt;/a&gt; language. As in, SEQUEL is the sequel to QUEL. Well... I guess QUEL got the last laugh because they had to change the name to SQL (Structured Query Language) due to trademark infringement.&lt;/p&gt;

&lt;p&gt;It wasn't until 1979 though, when &lt;a href="https://docs.oracle.com/database/121/SQLRF/intro001.htm#SQLRF50932"&gt;Relational Software, Inc. (now Oracle)&lt;/a&gt; introduced the first commercially available implementation of SQL in a relational database.&lt;/p&gt;

&lt;p&gt;That brings us to the other fundamental models we are going to cover today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The relational model -&amp;gt; relational databases&lt;/li&gt;
&lt;li&gt;The document model -&amp;gt; document databases&lt;/li&gt;
&lt;li&gt;The graph model -&amp;gt; graph databases&lt;/li&gt;
&lt;li&gt;Multi-model -&amp;gt; SurrealDB&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Relational databases -  like a jigsaw puzzle
&lt;/h2&gt;

&lt;p&gt;We have already touched on the origin of the relational model. However, we have yet to explore what it is.&lt;/p&gt;

&lt;p&gt;In the simplest terms, relational databases are like a jigsaw puzzle, where each puzzle piece represents an Excel-like table.&lt;/p&gt;

&lt;p&gt;One of the key innovations of the relational model is how you connect (or join) each puzzle piece together.&lt;/p&gt;

&lt;p&gt;The basic workflow for working with a relational database is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Plan how the puzzle pieces should look so they fit together (define a schema)&lt;/li&gt;
&lt;li&gt; Create the puzzle pieces (insert statements)&lt;/li&gt;
&lt;li&gt; Assemble the puzzle pieces (select queries)&lt;/li&gt;
&lt;li&gt; Then, you can see the complete picture of the puzzle (result set)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just like for jigsaw puzzles, for each picture you want to see, you might need to assemble many different puzzle pieces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Document model - like a Word document
&lt;/h2&gt;

&lt;p&gt;Now we come to the question people have been asking since the 1990s and will be asking for a long time. &lt;/p&gt;

&lt;p&gt;Why do we need other database models when we have the relational database model?&lt;/p&gt;

&lt;p&gt;It was because the internet was just getting started and becoming popular at the time.&lt;/p&gt;

&lt;p&gt;Since relational databases were not invented with the internet in mind (because the internet did not exist then), they became very slow. You can imagine the chaos of trying to organise 1000 or more people who want to work on assembling the same puzzle.&lt;/p&gt;

&lt;p&gt;Therefore the internet gave rise to other models like the document model.&lt;/p&gt;

&lt;p&gt;In the simplest terms, document databases are like a Word document, where you make sure that the document has all the relevant information in one place, kind of like this blog post.&lt;/p&gt;

&lt;p&gt;The thinking goes that it's easier to make 1000 copies of a single document for each of the 1000 people that need it rather than making 1000 puzzles, each with many oddly shaped puzzle pieces.&lt;/p&gt;

&lt;p&gt;This also gave rise to the term &lt;a href="https://en.wikipedia.org/wiki/Strozzi_NoSQL"&gt;NoSQL in 1998 by Carlo Strozzi&lt;/a&gt; who, interestingly enough, used it to describe a relational database which didn't use SQL. As we mentioned before, in the history of the relational model, SQL came much later as a way to implement the relational model, but it's entirely possible to find other ways to implement the relational model other than using standard SQL.&lt;/p&gt;

&lt;p&gt;However, NoSQL, which originally literally meant "No SQL", as in this database does not use SQL, is most commonly used to refer to databases that don't use the relational model.&lt;/p&gt;

&lt;p&gt;For example, MongoDB, a popular document database, which came out in 2009 uses the MongoDB Query Language (MQL).&lt;/p&gt;

&lt;p&gt;However, as relational databases started adopting internet technology and fixing the problem of how to organise the 1000 people who want to work on the same puzzle, people began wanting to use SQL in more and more places.&lt;/p&gt;

&lt;p&gt;That is why the term NoSQL changed meaning to "Not only SQL", as even popular databases like &lt;a href="https://www.mongodb.com/atlas/sql"&gt;MongoDB started adding support for SQL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The basic workflow for working with a document database is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Just like in a Word document, you just open a new document and start writing in all the information that you need.&lt;/li&gt;
&lt;li&gt;Then anyone can just read that document to get the information.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That works great when you don't have the time or the desire for so much upfront work of creating and solving a puzzle every time you want an answer.&lt;/p&gt;

&lt;p&gt;However, this apparent simplicity comes with other disadvantages. We won't touch on that much here except to say, which organisation doesn't have a problem organising Word documents? Important_document_v5_final_final.docx &lt;a href="https://www.mongodb.com/blog/post/building-with-patterns-the-document-versioning-pattern"&gt;seem familiar?&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Graph model - like your social network
&lt;/h2&gt;

&lt;p&gt;As we were searching for new ways to interact with this digital world, especially with the advent of e-commerce and social media, we found that it can be very tricky to express complex networks as text in Word documents (document model) or jigsaw puzzles (relational model).&lt;/p&gt;

&lt;p&gt;Therefore, a new mental model was needed to express complex networks more simply. In this new graph model, we think about relationships slightly differently than in the relational model.&lt;/p&gt;

&lt;p&gt;In the simplest terms, graph databases are like your social network, where when you're looking for help you might know somebody that knows somebody that can help you.&lt;/p&gt;

&lt;p&gt;The basic workflow for working with a graph database is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You make a map of who knows what and how they are connected&lt;/li&gt;
&lt;li&gt;Then, you ask around the network for what you want until you find it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Multi-model - SurrealDB
&lt;/h2&gt;

&lt;p&gt;If you've read this far, you might be beginning to understand why companies keep creating new databases. As the world keeps evolving, databases need to keep evolving as well. New technology enables us to take advantage of new ways of storing and sharing information.&lt;/p&gt;

&lt;p&gt;The question is, how should databases evolve?&lt;/p&gt;

&lt;p&gt;The answers to that generally fall into three categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let's make the relational model better. How oddly shaped we need to make the puzzle pieces doesn't matter. We can force them to fit using some clever tricks.&lt;/li&gt;
&lt;li&gt;Let's create a new model or new database for every different kind of task we have. If you could choose, wouldn't you choose the clothes that were tailor-made for you instead of the retail store clothes, which might be an awkward fit? &lt;/li&gt;
&lt;li&gt;What if we could do both? What if we could combine different innovative approaches to create a database that both feels custom tailored in its model flexibility but retains the simplicity we have come to expect from the relational model?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The third option is what we at SurrealDB have chosen, as we were &lt;a href="https://surrealdb.com/blog/dreaming-of-something-better"&gt;dreaming of something better&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;SurrealDB combines aspects of many different kinds of database models, including the major ones we talked about in the post. For an excellent technical introduction, you can &lt;a href="https://www.youtube.com/watch?v=C7WFwgDRStM"&gt;watch this short video&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the simplest terms, however, SurrealDB is like WD-40, use SurrealDB on problems that need lubricating for things to go much more smoothly. But, of course, if you want things to go smoothly from the beginning, you also use it as a preventative measure.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is just the start
&lt;/h2&gt;

&lt;p&gt;We have covered a lot of ideas and concepts in the post. If you want to learn more about the technical side and how to do CRUD practically across all these models and SurrealDB, subscribe so you don't miss our next post.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>database</category>
      <category>surrealdb</category>
    </item>
    <item>
      <title>Behind the scenes of the exciting beta 9 release</title>
      <dc:creator>Alexander Fridriksson</dc:creator>
      <pubDate>Thu, 13 Apr 2023 11:29:15 +0000</pubDate>
      <link>https://dev.to/surrealdb/behind-the-scenes-of-the-exciting-beta-9-release-3pe6</link>
      <guid>https://dev.to/surrealdb/behind-the-scenes-of-the-exciting-beta-9-release-3pe6</guid>
      <description>&lt;p&gt;Our team has been working very hard on the new release, which introduces a ton of new features, bug fixes and performance improvements &lt;a href="https://surrealdb.com/releases"&gt;you can see here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, the story of the beta 9 release is not about our team; it's about you!&lt;/p&gt;

&lt;p&gt;How you use the database and the ideas you have to improve it.&lt;/p&gt;

&lt;p&gt;Let's explore a few of these ideas and how they ended up getting released.&lt;/p&gt;

&lt;h2&gt;
  
  
  Returning a single field from &lt;code&gt;SELECT&lt;/code&gt; statements
&lt;/h2&gt;

&lt;p&gt;Brian (&lt;a href="https://github.com/Du-z"&gt;Du-z&lt;/a&gt;) joined our community last September and has made several great contributions, &lt;a href="https://github.com/surrealdb/surrealdb/issues/1326"&gt;including the one you’re reading about.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;He noticed that the query &lt;code&gt;SELECT name FROM user&lt;/code&gt; would result in something like the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Name 1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Name 2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, he felt it would be far easier to deserialize and work with a simple string array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"Name 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"Name 2"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;He gave this very helpful suggestion for a solution based on CosmosDB's &lt;code&gt;FIELD&lt;/code&gt; keyword:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT VALUE name FROM user&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After some discussion, this was implemented by our team, and now you can &lt;code&gt;SELECT VALUE name FROM user&lt;/code&gt;, thanks to Brian!&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom functions with &lt;code&gt;DEFINE FUNCTION&lt;/code&gt; statements
&lt;/h2&gt;

&lt;p&gt;Sebastian (&lt;strong&gt;&lt;a href="https://github.com/mathe42"&gt;mathe42&lt;/a&gt;&lt;/strong&gt;) has been a very active community member since last September, with around 20 pull requests and many other great contributions &lt;a href="https://github.com/surrealdb/surrealdb/issues/247"&gt;like this one&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For his use case, he was looking for some sort of user-defined functions that would allow us to have a callable list of SurrealQL instructions with arguments etc.&lt;/p&gt;

&lt;p&gt;He came up with this example of how it could be done:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Define a procedure to get a person&lt;/span&gt;

&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;get_person&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;birthdate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;firstname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;birthdate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;birthdate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
     &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;ELSE&lt;/span&gt;
    &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;birthdate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;birthdate&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;END&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;-- and call it by&lt;/span&gt;
&lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;myPerson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;CALL&lt;/span&gt; &lt;span class="n"&gt;get_person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Sebastian'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Krüger'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2022-09-21'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After some discussion and some magic from Tobie, you can now define global database-wide custom functions!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Define a global function which can be used in any query&lt;/span&gt;
&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get_person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;birthday&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;last&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;birthday&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;last&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;birthday&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
        &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;ELSE&lt;/span&gt;
        &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;last&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;birthday&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;birthday&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;-- Call the global custom function, receiving the returned result&lt;/span&gt;
&lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get_person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Tobie'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Morgan Hitchcock'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2022-09-21'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows complicated or repeated user-defined code to run seamlessly within any query across the database. &lt;/p&gt;

&lt;p&gt;Custom functions support typed arguments and multiple nested queries with custom logic.&lt;/p&gt;

&lt;p&gt;All this started with Sebastian’s idea for what he wanted in the database, thanks Sebastian!&lt;/p&gt;

&lt;h2&gt;
  
  
  Code blocks and advanced expressions
&lt;/h2&gt;

&lt;p&gt;Tom (&lt;strong&gt;&lt;a href="https://github.com/tomsseisums"&gt;tomsseisums&lt;/a&gt;&lt;/strong&gt;) also joined us on our journey in September and has been sharing some great insights into what can be done better, such as &lt;a href="https://github.com/surrealdb/surrealdb/issues/1319"&gt;this use case&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;He was trying to fit his project into SurrealDB from the perspective of "SurrealDB as a Backend", where with the power of SurrealDB, we could handle all data operations in SurrealDB without the need for any intermediate layer.&lt;/p&gt;

&lt;p&gt;He tried to set up events and fields with rich expressions in &lt;code&gt;CREATE&lt;/code&gt; / &lt;code&gt;UPDATE&lt;/code&gt; but was faced with parse errors.&lt;/p&gt;

&lt;p&gt;This is one of several things Tom was trying to do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;average_sales&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;count&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;p&gt;However he was disappointed when he received an unexpected parse error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"details"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Request problems detected"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"There is a problem with your request. Refer to the documentation for further information."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"information"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"There was a problem with the database: Parse error on line 1 at character 15 when parsing 'SET average_sales = (&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    LET $sales = (SELECT quantity FROM sales);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    LET $total = math::sum($sal'"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That didn’t stop him from wanting this to exist, and therefore he created a &lt;a href="https://github.com/surrealdb/surrealdb/issues/1319"&gt;feature request for it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After some discussion and some more magic, it is now possible, thanks to Tom!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;FIELD&lt;/span&gt; &lt;span class="n"&gt;average_sales&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt; &lt;span class="n"&gt;VALUE&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;count&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;p&gt;You can now run blocks of code with support for an arbitrary number of statements, including &lt;code&gt;LET&lt;/code&gt; and &lt;code&gt;RETURN&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;This allows for writing advanced custom logic and allows for more complicated handling of data operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thank you, everyone, for being a part of this ambitious journey with us!
&lt;/h2&gt;

&lt;p&gt;We only scratched the surface of what was released, and you can &lt;a href="https://surrealdb.com/releases"&gt;find more here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We are always happy to work on things together &lt;a href="https://github.com/surrealdb/surrealdb"&gt;on GitHub&lt;/a&gt; and &lt;a href="https://discord.gg/surrealdb"&gt;our Discord server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We’re looking forward to seeing what ideas and improvements you have in mind next!&lt;/p&gt;

&lt;p&gt;Until then we’ll be sharing more deep-dive blog posts about some of the new features coming out. &lt;/p&gt;

</description>
      <category>database</category>
      <category>surrealdb</category>
      <category>community</category>
    </item>
  </channel>
</rss>
