<?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: Nenad Ticaric</title>
    <description>The latest articles on DEV Community by Nenad Ticaric (@nticaric).</description>
    <link>https://dev.to/nticaric</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%2F136035%2F003353ae-92db-4c9d-830d-ea7fc8d95e5f.jpg</url>
      <title>DEV Community: Nenad Ticaric</title>
      <link>https://dev.to/nticaric</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nticaric"/>
    <language>en</language>
    <item>
      <title>Searching for users with Laravel Scout and TNTSearch</title>
      <dc:creator>Nenad Ticaric</dc:creator>
      <pubDate>Thu, 11 Mar 2021 09:57:58 +0000</pubDate>
      <link>https://dev.to/nticaric/searching-for-users-with-laravel-scout-and-tntsearch-3af4</link>
      <guid>https://dev.to/nticaric/searching-for-users-with-laravel-scout-and-tntsearch-3af4</guid>
      <description>&lt;p&gt;In almost every web application, a common requirement is a search feature.&lt;br&gt;
Clients are spoiled by Google and other search engines and expect a powerful search experience in their products. They don't realize the complexity behind it and just want it to work. Like they are used to.&lt;/p&gt;

&lt;p&gt;This tutorial will cover how to search your &lt;code&gt;users&lt;/code&gt; table and sequentially make yourself or your clients happy.&lt;/p&gt;

&lt;p&gt;It's most likely that your application has a &lt;code&gt;users&lt;/code&gt; table, and the client wants you to search over all the fields it contains. You'll probably come up with a solution that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rxIG8geW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/yvlcSAi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rxIG8geW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/yvlcSAi.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will certainly work for one keyword, but you'll face problems when you try to search for multiple keywords like &lt;code&gt;Taylor Otwell&lt;/code&gt;. So you dig deeper into your toolbox and write something like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LEa9JHaR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/jRCcPP2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LEa9JHaR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/jRCcPP2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, this will cover the case &lt;code&gt;Taylor Otwell&lt;/code&gt; but will have several downsides. This approach doesn't scale very well. If the wildcard &lt;code&gt;%&lt;/code&gt; operator is both on the left and right side of the query &lt;code&gt;%query%&lt;/code&gt;, the database's internal index cannot be leveraged, which means that the DB engine needs to go through every single row to see if there's a match. As you may know, that isn't nice... not to mention slow!&lt;/p&gt;

&lt;p&gt;If you introduce more fields, you'll have even more permutations in your code. You'll end up with a non performant and non readable query.&lt;/p&gt;

&lt;p&gt;The solution to this very problem comes in a &lt;a href="https://github.com/teamtnt/tntsearch"&gt;package&lt;/a&gt; written in pure PHP that deals with this stuff and lets you do some cool things. &lt;/p&gt;

&lt;p&gt;Laravel also introduced a driver based solution for full-text search which works nicely with TNTSearch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;p&gt;Lets see what the requirements are.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Composer&lt;/li&gt;
&lt;li&gt;PHP &amp;gt;= 7.1&lt;/li&gt;
&lt;li&gt;PDO PHP Extension&lt;/li&gt;
&lt;li&gt;SQLite PHP Extension&lt;/li&gt;
&lt;li&gt;mbstring PHP Extension&lt;/li&gt;
&lt;li&gt;Laravel Framework 5.6+&lt;/li&gt;
&lt;li&gt;TNTSearch&lt;/li&gt;
&lt;li&gt;Laravecl Scout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a pretty standard stack, and most of the hosting providers will come with all of the requirements. If not, you may consider switching to &lt;a href="https://m.do.co/c/ddfc227b7d18"&gt;Digital Ocean&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;The installation process is easy and can be done in a couple of simple steps&lt;/p&gt;

&lt;p&gt;&lt;code&gt;composer require teamtnt/laravel-scout-tntsearch-driver&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After that, add the service provider to &lt;code&gt;app/config/app.php&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SxUeLuZu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/Yz1gEH2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SxUeLuZu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/Yz1gEH2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add  &lt;code&gt;SCOUT_DRIVER=tntsearch&lt;/code&gt; to your &lt;code&gt;.env&lt;/code&gt; file&lt;/p&gt;

&lt;p&gt;Then you should publish the &lt;code&gt;scout.php&lt;/code&gt; configuration file to your config directory&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UChYyS0p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/NKl3zhO.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UChYyS0p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/NKl3zhO.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;config/scout.php&lt;/code&gt; add:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZzKHM5LZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/K4OLfvA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZzKHM5LZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/K4OLfvA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the index
&lt;/h3&gt;

&lt;p&gt;The first thing is creating the index so that we can search against it in milliseconds. You'll be amazed how fast it is.&lt;/p&gt;

&lt;p&gt;We'll create a laravel command that will do the indexing for us:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JaE3lk3P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/m7aeZ82.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JaE3lk3P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/m7aeZ82.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we have this command, we can run &lt;code&gt;php artisan index:users&lt;/code&gt;. This will create a file in your&lt;br&gt;
storage folder called &lt;code&gt;users.index&lt;/code&gt;. Now we are able to do queries against it.&lt;/p&gt;

&lt;p&gt;Another approach, and a more common one to achieve the same thing, is to add a searchable trait to your model:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cN1GUc71--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/2qIKmE9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cN1GUc71--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/2qIKmE9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then running:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan scout:import App\\Post&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That's it. The index has been created.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performing a search
&lt;/h3&gt;

&lt;p&gt;Performing the search is simple. We'll do this in our &lt;code&gt;UserController&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2A2dLR2B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/mYatfYF.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2A2dLR2B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/mYatfYF.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This controller assumes that you have a simple search form which submits a query in &lt;br&gt;
an input field called &lt;code&gt;q&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Updating the index manually isn't necessary because scout will do it automatically.&lt;/p&gt;

&lt;p&gt;What about scaling you may ask? Will it handle more than 100k users? Don't worry, it will scale fine even if you have millions of users. The index itself is a &lt;code&gt;sqlite&lt;/code&gt; database and is optimized for millions of records.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;As you saw from the tutorial, adding a full-text search to your project is pretty straightforward. We covered only the tip of the iceberg here. &lt;a href="https://github.com/teamtnt/tntsearch"&gt;TNTSearch&lt;/a&gt; is a powerful engine that can do a lot of stuff - even classification if that's something you might need. For more info, you can check out the GitHub documentation. &lt;/p&gt;

&lt;p&gt;We also created a &lt;a href="https://airports.tnt.studio/"&gt;cool demo&lt;/a&gt; for you so that you see the engine's power in action. It's an airport search that displays the results directly on the map in real-time. &lt;br&gt;
If you like it, leave a mention on twitter, and we might create a tutorial on how to do it.&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://tnt.studio/searching-for-users-with-laravel-scout-and-tntsearch"&gt;tnt.studio&lt;/a&gt; &lt;/p&gt;

</description>
      <category>laravel</category>
      <category>scout</category>
      <category>search</category>
      <category>tntsearch</category>
    </item>
  </channel>
</rss>
