Skip to content

Commit 64ddba9

Browse files
authored
DOCSP-48887: docs+ atlas search tutorial (#129)
* DOCSP-48887: docs+ atlas search tutorial * small fix * vale * tip * NR PR fixes 1 * wip
1 parent 0d860e5 commit 64ddba9

File tree

5 files changed

+341
-1
lines changed

5 files changed

+341
-1
lines changed

source/data-modeling/indexes.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ indexes in the ``Restaurant`` model:
166166
two documents with the same values for the ``_id`` field. You cannot
167167
drop this index.
168168

169+
.. _mongoid_indexes_atlas_search:
170+
169171
Atlas Search Indexes
170172
~~~~~~~~~~~~~~~~~~~~
171173

Loading

source/interact-data.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Interact with Data
2121
Search Text </interact-data/text-search>
2222
Transactions and Sessions </interact-data/transaction>
2323
Nested Attributes </interact-data/nested-attributes>
24+
Tutorial: Atlas Search </interact-data/atlas-search-tutorial>
2425

2526
In this section, you can learn how to use {+odm+} to interact with your
2627
MongoDB data.
@@ -44,4 +45,8 @@ MongoDB data.
4445
transactions to make atomic data changes.
4546

4647
- :ref:`mongoid-data-nested-attr`: Learn how to modify documents and
47-
their associations in a single operation.
48+
their associations in a single operation.
49+
50+
To learn how to integrate the Atlas Search feature into an application,
51+
see the :ref:`Integrate Atlas Search into a {+ror+} App Tutorial
52+
<mongoid-atlas-search-rails-tutorial>`.
Lines changed: 330 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,330 @@
1+
.. _mongoid-atlas-search-rails-tutorial:
2+
3+
=========================================================
4+
Tutorial: Integrate Atlas Search into a {+ror+} App
5+
=========================================================
6+
7+
.. facet::
8+
:name: genre
9+
:values: reference
10+
11+
.. meta::
12+
:keywords: code example, transform, pipeline
13+
14+
.. contents:: On this page
15+
:local:
16+
:backlinks: none
17+
:depth: 2
18+
:class: singlecol
19+
20+
Overview
21+
--------
22+
23+
In this tutorial, you can learn how to integrate :atlas:`Atlas Search
24+
</atlas-search/>`, an advanced text search feature, into a {+ror+} app.
25+
26+
After you complete this tutorial, you have a fully functional search
27+
feature embedded in your Rails app, allowing you to efficiently find
28+
information.
29+
30+
Prerequisites
31+
-------------
32+
33+
The tutorial builds on a template app that you can download from the
34+
:github:`mongodb-atlas-with-ruby-on-rails-example GitHub repository
35+
<mongodb-developer/mongodb-atlas-with-ruby-on-rails-example>` by running
36+
the following command:
37+
38+
.. code-block:: bash
39+
40+
git clone https://github.com/mongodb-developer/mongodb-atlas-with-ruby-on-rails-example.git
41+
42+
Then, perform the following setup actions:
43+
44+
1. Create a MongoDB Atlas cluster. To learn how to create a cluster, see
45+
the :ref:`mongoid-quick-start-rails-create-deployment` step of the
46+
Rails Quick Start guide.
47+
48+
#. Update the app's ``config/mongoid.yml`` file with your own connection
49+
string and set the default database to ``inspiration``, as shown the
50+
following example configuration:
51+
52+
.. code-block:: yml
53+
54+
development:
55+
clients:
56+
default:
57+
uri: mongodb+srv://<username>:<password>@<host>/inspiration
58+
59+
#. Start the Rails app by running the ``rails server`` command, then
60+
complete the :guilabel:`New Idea` entry form to insert some sample
61+
data into the ``inspiration.ideas`` collection.
62+
63+
.. tip:: Sample Data
64+
65+
To achieve the search functionality demonstrated later in
66+
the tutorial, insert sample documents that contain some overlapping
67+
terms in the ``name`` or ``description`` fields.
68+
69+
#. Create an Atlas Search index in Compass or the Atlas UI called
70+
``inspiration`` with dynamic (default) mappings. To learn more about
71+
creating Atlas Search indexes, see the
72+
:ref:`mongoid_indexes_atlas_search` section of the Indexes guide.
73+
74+
Steps
75+
-----
76+
77+
.. procedure::
78+
:style: connected
79+
80+
.. step:: Configure the Atlas Search feature in your {+odm+} model.
81+
82+
First, update the ``Idea`` model to handle Atlas Search queries on
83+
the ``ideas`` collection by defining the ``search`` method in the
84+
model. The method ``self.search(query)`` defines a class method
85+
called ``search`` that takes a single argument ``query`` and
86+
returns the search results.
87+
88+
Open the ``app/models/idea.rb`` file and replace its contents with
89+
the following code:
90+
91+
.. code-block:: ruby
92+
93+
class Idea
94+
include Mongoid::Document
95+
include Mongoid::Timestamps
96+
field :name, type: String
97+
field :description, type: String
98+
field :picture, type: String
99+
100+
def self.search(query)
101+
aggregation_pipeline = [
102+
{
103+
"$search": {
104+
"index": "inspiration",
105+
"text": {
106+
"query": query,
107+
"path": ['name', 'description']
108+
},
109+
"sort": {
110+
"score": { "$meta": "searchScore" }
111+
}
112+
}
113+
},
114+
{
115+
"$limit": 20
116+
}
117+
]
118+
results = collection.aggregate(aggregation_pipeline)
119+
120+
search_results = results.to_a
121+
search_results.map do |result|
122+
Idea.new(
123+
id: result["_id"],
124+
name: result["name"],
125+
description: result["description"],
126+
picture: result["picture"]
127+
)
128+
end
129+
end
130+
end
131+
132+
When you call ``idea.search("<example query>")``, {+odm+} performs the
133+
following actions:
134+
135+
1. Performs a full-text search by using the ``inspiration`` index.
136+
#. Runs the query across the ``name`` and ``description`` fields.
137+
#. Sorts the results by their relevance scores.
138+
#. Limits the number of results to ``20`` to improve performance
139+
for queries on large collections.
140+
141+
The ``search_results`` variable then converts the raw results from
142+
MongoDB into an array of hashes that can be mapped to ``Idea``
143+
model instances and rendered in your view files.
144+
145+
.. step:: Add a Search action in your controller.
146+
147+
Now that you defined the Search query functionality in the
148+
``Idea`` model, you must add an action to initiate queries.
149+
150+
Open the ``app/controllers/ideas_controller.rb`` file and add the
151+
following action to your ``IdeasController`` before the ``private``
152+
declaration:
153+
154+
.. code-block:: ruby
155+
156+
def search
157+
@query = params[:query]
158+
@ideas = @query.present? ? Idea.search(@query) : Idea.all
159+
render :display_results
160+
end
161+
162+
Now, when you submit a Search query, {+odm+} runs the
163+
``search`` method in the ``Idea`` model. The
164+
results are then rendered in your view files.
165+
166+
.. step:: Generate the Search controller.
167+
168+
Run the following command to generate the ``SearchesController``
169+
and the ``display_results`` view file, which handle ``search``
170+
requests and display the results, respectively:
171+
172+
.. code-block:: bash
173+
174+
rails generate controller Searches display_results
175+
176+
Open the newly created ``searches_controller.rb`` file and replace
177+
the contents with the following code:
178+
179+
.. code-block:: ruby
180+
181+
class SearchesController < ApplicationController
182+
def display_results
183+
query = params[:query]
184+
@results = Idea.search(query)
185+
end
186+
end
187+
188+
Open the ``app/views/searches/display_results.html.erb`` file and
189+
replace the contents with the following code, which renders the search results:
190+
191+
.. code-block:: html
192+
193+
<div class="search-results">
194+
<h1>Search Results for "<%= params[:query] %>"</h1>
195+
196+
<% if @results.empty? %>
197+
<p>No ideas found.</p>
198+
<% else %>
199+
<div class="idea-container">
200+
<% @results.each do |result| %>
201+
<div class="idea">
202+
<h2><%= result.name %></h2>
203+
<p><%= truncate(result.description, length: 150) %></p>
204+
<img src="<%= result.picture %>" alt="<%= result.name %>" />
205+
206+
<p><%= link_to "View", idea_path(result.id) %></p>
207+
</div>
208+
<% end %>
209+
</div>
210+
<% end %>
211+
</div>
212+
213+
<%= link_to "Back", ideas_path %>
214+
215+
Then, add the following code to your ``app/assets/stylesheets/application.css`` file to include
216+
basic styling for the search results:
217+
218+
.. code-block:: css
219+
220+
.search-results {
221+
width: 80%;
222+
margin: 0 auto;
223+
}
224+
.idea-container {
225+
display: flex;
226+
flex-direction: column;
227+
}
228+
.idea {
229+
padding: 20px;
230+
border-bottom: 2px solid #ccc;
231+
border-radius: 10px 10px 0 0;
232+
margin-bottom: 10px;
233+
}
234+
.idea h2 {
235+
margin: 0;
236+
}
237+
.idea p {
238+
margin: 0;
239+
}
240+
.idea img {
241+
width: 100px;
242+
height: auto;
243+
display: block;
244+
}
245+
ul {
246+
list-style-type: none;
247+
padding: 0;
248+
}
249+
250+
.. step:: Create the Search form.
251+
252+
To enable Search queries directly in your application, open the
253+
``app/views/ideas/index.html.erb`` file and add the following
254+
code:
255+
256+
.. code-block:: html
257+
258+
<%= form_tag(search_results_path, method: :get, class: "form-inline") do %>
259+
<div class="input-group mb-3">
260+
<%= text_field_tag :query, params[:query], placeholder: "Search Ideas...", class: "form-control" %>
261+
<div class="input-group-append">
262+
<%= submit_tag "Search", class: "btn btn-primary text-white" %>
263+
</div>
264+
</div>
265+
<% end %>
266+
267+
Add the following styling for the search bar to your ``application.css`` file:
268+
269+
.. code-block:: css
270+
271+
.input-group {
272+
width: 100%;
273+
}
274+
.btn-primary {
275+
background-color: #007bff;
276+
border-color: #007bff;
277+
color: white;
278+
}
279+
.btn-primary:hover {
280+
background-color: #0056b3;
281+
border-color: #004085;
282+
}
283+
284+
.. step:: Update app routes for Search queries.
285+
286+
Replace the existing route in the ``config/routes.rb`` file with
287+
following route to display search results:
288+
289+
.. code-block:: ruby
290+
291+
Rails.application.routes.draw do
292+
root to: "ideas#index"
293+
resources :ideas
294+
get '/search_results', to: 'searches#display_results', as: "search_results"
295+
end
296+
297+
.. step:: Start your application and run Search queries.
298+
299+
In your project directory, run the following command to start your
300+
application:
301+
302+
.. code-block:: bash
303+
304+
rails server
305+
306+
Navigate to http://127.0.0.1:3000/ to view the landing page.
307+
308+
To submit a query, type a term or phrase in the search bar then
309+
click the :guilabel:`Search` button. The following image depicts
310+
the search results for the term ``"outdoor"``:
311+
312+
.. figure:: /includes/figures/atlas-search-tutorial-render.png
313+
:alt: The rendered Search results
314+
315+
The search results depend on the documents in your
316+
database. As the complexity of your data increases, you might need
317+
to perform more advanced queries to narrow results. To learn more
318+
about different Atlas Search queries and view examples, see the
319+
:atlas:`Query Reference </atlas-search/query-ref/>` in the Atlas
320+
documentation.
321+
322+
Conclusion
323+
----------
324+
325+
In this tutorial, you learned how to integrate the Atlas Search feature
326+
into a Rails application. This integration enhances usability and
327+
functionality while improving user engagement.
328+
329+
To learn more about performing queries in {+odm+}, see the
330+
:ref:`mongoid-interact-data` guides.

source/quick-start-rails/next-steps.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,6 @@ Learn more about {+odm+} features from the following sections:
2828

2929
- :ref:`mongoid-interact-data`: Learn how to interact with your MongoDB
3030
data by using {+odm+} models.
31+
32+
- :ref:`mongoid-atlas-search-rails-tutorial`: Learn how to integrate the
33+
Atlas Search feature into your application.

0 commit comments

Comments
 (0)