Skip to content

Commit eff4e1d

Browse files
first pass aggregation
1 parent e894402 commit eff4e1d

File tree

4 files changed

+224
-7
lines changed

4 files changed

+224
-7
lines changed

snooty.toml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
name = "mongoid"
22
title = "Mongoid"
33

4-
intersphinx = [ "https://www.mongodb.com/docs/manual/objects.inv",
5-
"https://www.mongodb.com/docs/atlas/objects.inv"
6-
]
4+
intersphinx = [
5+
"https://www.mongodb.com/docs/manual/objects.inv",
6+
"https://www.mongodb.com/docs/atlas/objects.inv",
7+
]
78

8-
toc_landing_pages = [
9-
"/quick-start-rails",
10-
"/quick-start-sinatra"
11-
]
9+
toc_landing_pages = ["/quick-start-rails", "/quick-start-sinatra"]
1210

1311
[constants]
1412
rails-6-version = 6.0
@@ -22,3 +20,4 @@ quickstart-sinatra-app-name = "my-sinatra-app"
2220
quickstart-rails-app-name = "my-rails-app"
2321
feedback-widget-title = "Feedback"
2422
server-manual = "Server manual"
23+
api-root = "https://www.mongodb.com/docs/mongoid/master/api/Mongoid"

source/aggregation.txt

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
.. _mongoid-aggregation:
2+
3+
====================================
4+
Transform Your Data with Aggregation
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: 1
18+
:class: singlecol
19+
20+
Overview
21+
--------
22+
23+
In this guide, you can learn how to use {+odm+} to perform **aggregation
24+
operations**.
25+
26+
Aggregation operations process data in your MongoDB collections and return
27+
computed results. The MongoDB Aggregation framework, which is part of the Query
28+
API, is modeled on the concept of data processing pipelines. Documents enter a
29+
pipeline that contains one or more stages, and this pipeline transforms the
30+
documents into an aggregated result.
31+
32+
An aggregation operation is similar to a car factory. A car factory has an assembly line, which contains assembly stations with specialized tools to do specific jobs, like drills and welders. Raw parts enter the factory, and then the assembly line transforms and assembles them into a finished product.
33+
34+
The **aggregation pipeline** is the assembly line, **aggregation stages** are the
35+
assembly stations, and **operator expressions** are the specialized tools.
36+
37+
Aggregation Versus Find Operations
38+
----------------------------------
39+
40+
You can use find operations to perform the following actions:
41+
42+
- Select which documents to return
43+
- Select which fields to return
44+
- Sort the results
45+
46+
You can use aggregation operations to perform the following actions:
47+
48+
- Run find operations
49+
- Rename fields
50+
- Summarize data
51+
- Group values
52+
53+
{+odm+} Builders
54+
----------------
55+
56+
You can construct an aggregation pipeline by using {+odm+}'s high-level
57+
domain-specific language (DSL). The DSL supports the following aggregation
58+
pipeline operators:
59+
60+
.. list-table::
61+
:header-rows: 1
62+
:widths: 10 90
63+
:class: table-bordered
64+
65+
* - Operator
66+
- Method Name
67+
68+
* - :manual:`$group <reference/operator/aggregation/group/>`
69+
- ``group()``
70+
71+
* - :manual:`$project <reference/operator/aggregation/project/>`
72+
- ``project()``
73+
74+
* - :manual:`$unwind <reference/operator/aggregation/unwind/>`
75+
- ``unwind()``
76+
77+
To create an aggregation pipeline by using one of the preceding operators, call
78+
the corresponding method on an instance of ``Criteria``. Calling the method adds
79+
the aggregation operation to the ``pipelin`` atrritbure of the ``Criteria``
80+
instance. To run the aggregation pipeline, pass the ``pipeline`` attribute value
81+
to the ``Collection#aggregate()`` method.
82+
83+
Example
84+
~~~~~~~
85+
86+
Consider a collection that contains documents that are modeled as follows:
87+
88+
.. code-block:: ruby
89+
90+
class Tour
91+
include Mongoid::Document
92+
93+
embeds_many :participants
94+
95+
field :name, type: String
96+
field :states, type: Array
97+
end
98+
99+
class Participant
100+
include Mongoid::Document
101+
102+
embedded_in :tour
103+
104+
field :name, type: String
105+
end
106+
107+
The following example creates an aggregation pipeline that outputs the states a
108+
participant has visited by using the following
109+
aggregation operations:
110+
111+
- ``$match``, which find documents in which the ``participants.name`` field
112+
value is ``"Serenity"``
113+
- ``$unwind``, which deconstructs the ``states`` array field and outputs a
114+
document for each element in the array
115+
- ``$group``, which groups the documents by the value of their ``states`` field
116+
- ``$project``, which prompts the pipeline to return only the ``_id`` and
117+
``states`` fields
118+
119+
.. literalinclude:: /includes/aggregation/builder-dsl.rb
120+
:language: ruby
121+
122+
Aggregation with the Ruby Driver
123+
--------------------------------
124+
125+
You can use the Ruby driver to run aggregation operations that do not have
126+
corresponding builder methods by using the
127+
``Collection#aggregate()`` method, and passing in an array of aggregation
128+
operations. Creating the aggregation pipeline by using the Ruby driver returns
129+
raw ``BSON::Document`` objects rather than ``Mongoid::Document`` model
130+
instances.
131+
132+
Example
133+
~~~~~~~
134+
135+
Consider a collection that contains documents that are modeled as follows:
136+
137+
.. code-block:: ruby
138+
139+
class Band
140+
include Mongoid::Document
141+
has_many :tours
142+
has_many :awards
143+
field :name, type: String
144+
end
145+
146+
class Tour
147+
include Mongoid::Document
148+
belongs_to :band
149+
field :year, type: Integer
150+
end
151+
152+
class Award
153+
include Mongoid::Document
154+
belongs_to :band
155+
field :name, type: String
156+
end
157+
158+
The following example creates an aggregation pipeline to retrieve all bands that
159+
have toured since 2010 and have at least one or more awards:
160+
161+
.. literalinclude:: /includes/aggregation/ruby-aggregation.rb
162+
:language: ruby
163+
164+
.. tip::
165+
166+
The preceding example projects only the ``_id`` field of the output
167+
documents. It then uses the ``_id`` field to find the documents and return
168+
them as ``Mongoid::Document`` model instances. This optional step is not
169+
required to run an aggregation pipeline.
170+
171+
Additional Information
172+
----------------------
173+
174+
To view a full list of aggregation operators, see :manual:`Aggregation
175+
Operators. </reference/operator/aggregation/>`
176+
177+
To learn about assembling an aggregation pipeline and view examples, see
178+
:manual:`Aggregation Pipeline. </core/aggregation-pipeline/>`
179+
180+
To learn more about creating pipeline stages, see :manual:`Aggregation
181+
Stages. </reference/operator/aggregation-pipeline/>`
182+
183+
API Documentation
184+
~~~~~~~~~~~~~~~~~
185+
186+
To learn more about any of the methods discussed in this
187+
guide, see the following API documentation:
188+
189+
- `group() <{+api-root+}/Criteria/Queryable/Aggregable.html#group-instance_method>`__
190+
- `project() <{+api-root+}/Criteria/Queryable/Aggregable.html#project-instance_method>`__
191+
- `unwind() <{+api-root+}/Criteria/Queryable/Aggregable.html#unwind-instance_method>`__
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
criteria = Tour.where('participants.name' => 'Serenity').
2+
unwind(:states).
3+
group(_id: 'states', :states.add_to_set => '$states').
4+
project(_id: 0, states: 1)
5+
6+
Tour.collection.aggregate(criteria.pipeline).to_a
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
band_ids = Band.collection.aggregate([
2+
{ '$lookup' => {
3+
from: 'tours',
4+
localField: '_id',
5+
foreignField: 'band_id',
6+
as: 'tours',
7+
} },
8+
{ '$lookup' => {
9+
from: 'awards',
10+
localField: '_id',
11+
foreignField: 'band_id',
12+
as: 'awards',
13+
} },
14+
{ '$match' => {
15+
'tours.year' => {'$gte' => 2000},
16+
'awards._id' => {'$exists' => true},
17+
} },
18+
{'$project' => {_id: 1}},
19+
])
20+
21+
bands = Band.find(band_ids.to_a)

0 commit comments

Comments
 (0)