Skip to content

Commit 1a5bac2

Browse files
authored
Merge pull request #59 from rustagir/DOCSP-44849-modify-results
DOCSP-44849: modify results
2 parents 3e498c6 + 1616f65 commit 1a5bac2

File tree

4 files changed

+349
-0
lines changed

4 files changed

+349
-0
lines changed

snooty.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ quickstart-sinatra-app-name = "my-sinatra-app"
2323
quickstart-rails-app-name = "my-rails-app"
2424
feedback-widget-title = "Feedback"
2525
server-manual = "Server manual"
26+
api = "https://www.mongodb.com/docs/mongoid/master/api"
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# start-only
2+
Band.where(members: 4).only(:name)
3+
# end-only
4+
5+
# start-only-embed
6+
bands = Band.only(:name, 'tours.year')
7+
# end-only-embed
8+
9+
# start-only-embed-association
10+
# Returns null
11+
Band.where(name: 'Astral Projection').only(:name).first.managers
12+
13+
# Returns the first Manager object
14+
Band.where(name: 'Astral Projection').only(:name, :manager_ids).first.managers
15+
# end-only-embed-association
16+
17+
# start-without
18+
Band.where(members: 4).without(:year)
19+
# end-without
20+
21+
# start-limit
22+
Band.limit(5)
23+
# end-limit
24+
25+
# start-skip-limit
26+
Band.skip(2).limit(5)
27+
# Skips the first two results and returns
28+
# the following five results
29+
# end-skip-limit
30+
31+
# start-skip
32+
Band.skip(3)
33+
34+
# Equivalent
35+
Band.offset(3)
36+
# end-skip
37+
38+
# start-batch
39+
Band.batch_size(500)
40+
# end-batch

source/interact-data.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@ Interact with Data
1515
:caption: Interact with Data
1616

1717
/interact-data/specify-query
18+
/interact-data/modify-results
1819

1920
In this section, you can learn how to use {+odm+} to interact with your
2021
MongoDB data.
2122

2223
- :ref:`mongoid-data-specify-query`: Learn how to construct
2324
queries to match specific documents in a MongoDB collection.
25+
26+
- :ref:`mongoid-data-modify-results`: Learn how to modify the way that
27+
{+odm+} returns results from queries.
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
.. _mongoid-data-modify-results:
2+
3+
====================
4+
Modify Query Results
5+
====================
6+
7+
.. facet::
8+
:name: genre
9+
:values: reference
10+
11+
.. meta::
12+
:keywords: ruby framework, odm, crud, print results, code example
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 guide, you can learn how to customize the way that {+odm+}
24+
returns results from queries. MongoDB allows you to perform the
25+
following actions to modify the way that results appear:
26+
27+
- :ref:`mongoid-data-projection`
28+
29+
- :ref:`mongoid-data-sort`
30+
31+
- :ref:`mongoid-data-skip-limit`
32+
33+
Sample Data
34+
~~~~~~~~~~~
35+
36+
The examples in this guide use the ``Band`` model, which represents a
37+
band or musical group. The definition of the ``Band`` model might be
38+
different for each section to demonstrate different query
39+
functionalities. Some sections also use the ``Manager`` model,
40+
which represents a person who manages a given band, or the ``Tour``
41+
model, which represents live performances by a given band.
42+
43+
.. _mongoid-data-projection:
44+
45+
Return Specified Fields
46+
-----------------------
47+
48+
In MongoDB, *projection* is the process of specifying fields to include
49+
or exclude from results. {+odm+} provides the following operators
50+
to project fields:
51+
52+
- ``only()``: Specifies fields to include
53+
- ``without()``: Specifies fields to exclude
54+
55+
Include Fields
56+
~~~~~~~~~~~~~~
57+
58+
The ``only()`` method retrieves only the specified fields from the
59+
database.
60+
61+
The following code returns only the ``name`` field from documents in
62+
which the value of the ``members`` field is ``4``:
63+
64+
.. literalinclude:: /includes/interact-data/modify-results.rb
65+
:start-after: start-only
66+
:end-before: end-only
67+
:language: ruby
68+
:dedent:
69+
70+
.. note:: _id Field
71+
72+
In MongoDB, the ``_id`` field is included in results even if you do
73+
not explicitly include it.
74+
75+
If you attempt to reference attributes that have not been loaded,
76+
{+odm+} raises a ``Mongoid::Errors::AttributeNotLoaded`` error.
77+
78+
You can also use the ``only()`` method to include fields from embedded
79+
documents.
80+
81+
Consider that the ``Band`` model embeds multiple ``Tour`` objects. You can
82+
project fields from the ``Tour`` model such as ``year``, as shown in the
83+
following code:
84+
85+
.. literalinclude:: /includes/interact-data/modify-results.rb
86+
:start-after: start-only-embed
87+
:end-before: end-only-embed
88+
:language: ruby
89+
:dedent:
90+
91+
Then, you can access the embedded fields from the returned documents:
92+
93+
.. code-block:: ruby
94+
95+
# Returns the first Tour object from
96+
# the first Band in the results
97+
bands.first.tours.first
98+
99+
You can pass fields of referenced associations to the ``only()`` method,
100+
but the projection is ignored when loading the embedded objects. {+odm+}
101+
loads all fields of the referenced associations. For example, when you
102+
access the embedded ``Tour`` object as shown in the preceding code,
103+
{+odm+} returns the complete object, not just the ``year`` field.
104+
105+
.. note::
106+
107+
If you are connected to a deployment running MongoDB 4.4 or later,
108+
you cannot specify an association and its fields in a projection in
109+
the same query.
110+
111+
If a document contains ``has_one`` or ``has_and_belongs_to_many``
112+
associations, and you want {+odm+} to load those associations when
113+
you call the ``only()`` method, you must include the fields with foreign
114+
keys in the list of attributes.
115+
116+
In the following example, the ``Band`` and ``Manager`` models have a
117+
``has_and_belongs_to_many`` association:
118+
119+
.. code-block:: ruby
120+
121+
class Band
122+
include Mongoid::Document
123+
field :name, type: String
124+
has_and_belongs_to_many :managers
125+
end
126+
127+
class Manager
128+
include Mongoid::Document
129+
has_and_belongs_to_many :bands
130+
end
131+
132+
The following code demonstrates how {+odm+} can load the associated
133+
``Manager`` objects if you include the ``manager_ids`` field:
134+
135+
.. literalinclude:: /includes/interact-data/modify-results.rb
136+
:start-after: start-only-embed-association
137+
:end-before: end-only-embed-association
138+
:language: ruby
139+
:dedent:
140+
141+
Exclude Fields
142+
~~~~~~~~~~~~~~
143+
144+
You can explicitly exclude fields from results by using the
145+
``without()`` method.
146+
147+
The following code excludes the ``year`` field from returned ``Band``
148+
objects:
149+
150+
.. literalinclude:: /includes/interact-data/modify-results.rb
151+
:start-after: start-without
152+
:end-before: end-without
153+
:language: ruby
154+
:dedent:
155+
156+
.. important:: _id Field
157+
158+
{+odm+} requires the ``_id`` field for various operations, so you
159+
*cannot* exclude the ``_id`` field or the ``id`` alias from results.
160+
If you pass ``_id`` or ``id`` to the ``without()`` method, {+odm+}
161+
ignores it.
162+
163+
.. _mongoid-data-sort:
164+
165+
Sort Results
166+
------------
167+
168+
You can specify the order in which {+odm+} returns documents by using the
169+
``order()`` and ``order_by()`` methods.
170+
171+
These methods accept a hash that indicates which fields to order the
172+
documents by, and whether to use an ascending or descending order for
173+
each field.
174+
175+
You can specify the sort direction by using integers, symbols, or
176+
strings. We recommend using the same sorting syntax throughout your
177+
application for consistency. The following list provides each syntax and
178+
shows how to sort on the ``name`` and ``year`` fields:
179+
180+
- Integers ``1`` (ascending) and ``-1`` (descending)
181+
182+
- Example: ``Band.order(name: 1, year: -1)``
183+
184+
- Symbols ``:asc`` and ``:desc``
185+
186+
- Example: ``Band.order(name: :asc, year: :desc)``
187+
188+
- Strings ``"asc"`` and ``"desc"``
189+
190+
- Example: ``Band.order_by(name: "asc", year: "desc")``
191+
192+
The ``order()`` method also accepts the following sort specifications:
193+
194+
- Array of two-element arrays:
195+
196+
- Strings
197+
198+
- Example: ``Band.order([['name', 'asc'], ['year', 'desc']])``
199+
200+
- Symbols
201+
202+
- Example: ``Band.order([[:name, :asc], [:year, :desc]])``
203+
204+
- ``asc`` and ``desc`` methods on symbols
205+
206+
- Example: ``Band.order(:name.asc, :year.desc)``
207+
208+
- SQL syntax
209+
210+
- Example: ``Band.order('name asc', 'year desc')``
211+
212+
.. tip::
213+
214+
Instead of using ``order()`` or ``order_by()``, you can also use the
215+
``asc()`` and ``desc()`` methods to specify sort orders:
216+
217+
.. code-block:: ruby
218+
219+
Band.asc('name').desc('year')
220+
221+
When you chain sort specifications, the first call defines the first
222+
sorting order and the newest call defines the last sorting order after
223+
the previous sorts have been applied.
224+
225+
.. TODO update link in the following note for scope
226+
227+
.. note:: Sorting in Scopes
228+
229+
If you define a scope on your model that includes a sort specification,
230+
the scope sort takes precedence over the sort specified in a query,
231+
because the default scope is evaluated first.
232+
233+
.. _mongoid-data-skip-limit:
234+
235+
Paginate Results
236+
----------------
237+
238+
{+odm+} provides the ``limit()``, ``skip()``, and ``batch_size()``
239+
pagination methods that you can use on ``Criteria`` objects. The
240+
following sections describe how to use these operators.
241+
242+
Limit Number of Results
243+
~~~~~~~~~~~~~~~~~~~~~~~
244+
245+
You can use the ``limit()`` method to limit the number of results that
246+
{+odm+} returns.
247+
248+
The following code retrieves a maximum of ``5`` documents:
249+
250+
.. literalinclude:: /includes/interact-data/modify-results.rb
251+
:start-after: start-limit
252+
:end-before: end-limit
253+
:language: ruby
254+
:dedent:
255+
256+
Skip Results
257+
~~~~~~~~~~~~
258+
259+
You can skip a specified number of results by using the ``skip()``
260+
method, or its alias ``offset()``.
261+
262+
If you chain a ``limit()`` call to ``skip()``, the limit is applied
263+
after documents are skipped, as demonstrated in the following example:
264+
265+
.. literalinclude:: /includes/interact-data/modify-results.rb
266+
:start-after: start-skip-limit
267+
:end-before: end-skip-limit
268+
:language: ruby
269+
:dedent:
270+
271+
.. tip::
272+
273+
When performing pagination, use ``skip()`` on :ref:`sorted results <mongoid-data-sort>`
274+
to ensure consistent results.
275+
276+
The following code skips the first ``3`` documents when returning results:
277+
278+
.. literalinclude:: /includes/interact-data/modify-results.rb
279+
:start-after: start-skip
280+
:end-before: end-skip
281+
:language: ruby
282+
:dedent:
283+
284+
Generate Batches of Results
285+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
286+
287+
When executing large queries and when iterating over query results by using
288+
an enumerator method such as ``Criteria#each()``, {+odm+} automatically
289+
uses the MongoDB :manual:`getMore </reference/command/getMore/>` command
290+
to load results in batches. The default batch size is ``1000``, but
291+
you can set a different value by using the ``batch_size()`` method.
292+
293+
The following code sets the batch size to ``500``:
294+
295+
.. literalinclude:: /includes/interact-data/modify-results.rb
296+
:start-after: start-batch
297+
:end-before: end-batch
298+
:language: ruby
299+
:dedent:
300+
301+
Additional Information
302+
----------------------
303+
304+
.. TODO: add links to the bottom of this page

0 commit comments

Comments
 (0)