Skip to content

Commit 56ce8cd

Browse files
committed
Added $merge
1 parent 20499d3 commit 56ce8cd

File tree

2 files changed

+209
-5
lines changed

2 files changed

+209
-5
lines changed

docs/80-modifying-results/missing-data.mdx

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
---
2+
sidebar_position: 90
3+
---
4+
15
import Tabs from '@theme/Tabs';
26
import TabItem from '@theme/TabItem';
37

docs/90-exporting-data/saving-to-collection.mdx

+205-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import TabItem from '@theme/TabItem';
33

44
# 🦸 Saving to a Collection
55

6-
You can export the result of an aggregation pipeline to a different DB/collection. To do that, just add a last aggregation stage to your pipeline:
6+
# $out
7+
8+
You can export the result of an aggregation pipeline to a different DB/collection. To do that, just add a last aggregation stage `$out` to your pipeline:
79

810
<Tabs groupId="aggregations">
911
<TabItem value="atlas" label="Atlas UI">
@@ -33,6 +35,11 @@ You can omit the `db` attribute, and the new collection will be created in the c
3335
{ $out: "<output-collection>" }
3436
```
3537

38+
:::info
39+
The `$out` stage must be the last stage in the pipeline.
40+
:::
41+
42+
3643
👐 Create a copy of the books with exactly 100 pages and output as a new collection named `OneHundredPagesBooks`.
3744

3845
<details>
@@ -49,6 +56,8 @@ You can omit the `db` attribute, and the new collection will be created in the c
4956
]
5057
```
5158

59+
Refresh the database to see the new collection.
60+
5261
</TabItem>
5362

5463
<TabItem value="mongodb-shell" label="MongoDB Shell">
@@ -63,15 +72,206 @@ db.books.aggregate([
6372
]);
6473
```
6574

75+
After running this, we should see a new collection with:
76+
77+
```js
78+
show collections
79+
```
6680
</TabItem>
6781
</Tabs>
6882

6983

7084

71-
After running this, we should see a new collection with:
85+
</div>
86+
</details>
87+
88+
---
89+
90+
Reference: [📗 `$out` documentation](https://www.mongodb.com/docs/manual/reference/operator/aggregation/out/)
91+
92+
## Merging output results
93+
94+
If the collection specified by the `$out` operation already exists, then the `$out` stage atomically replaces the existing collection with the new results collection upon completion of the aggregation.
95+
96+
To avoid overwriting the existing collection we can use `$merge` instead of `$out`.
97+
98+
```
99+
{ $merge : { into : "newCollection" } }
100+
```
101+
102+
- if the collection does not exists, it will be created
103+
- if it exists, new data will be added
104+
- if [a doc already exists](https://www.mongodb.com/docs/manual/reference/operator/aggregation/merge/#std-label-merge-whenMatched), we can replace it, keep the existing one, merge both documents cause the stage to fail or run a pipeline.
105+
106+
This is perfect for creating [On-Demand Materialized Views](https://www.mongodb.com/docs/manual/core/materialized-views/)
107+
108+
As an example, let's say we want the authors to contain all the books they've written, with all the book information. In this case, we'll do a `$lookup` to get the book information into the authors collection. We can even use the name `books` for the resulting data we're joining, shadowing the original `books` array we have in authors. This way it will look like the `books` array changes.
72109

73110
```js
74-
show collections
111+
[
112+
{$lookup: {
113+
from: "books",
114+
localField: "books",
115+
foreignField: "_id",
116+
as: "books"
117+
}
118+
},
119+
]
75120
```
76-
</div>
77-
</details>
121+
122+
Now a book will look like this. You can see that the books array has been "overwritten" by the `$lookup`.
123+
124+
```js
125+
{
126+
"name": "Richard Bruce Wright",
127+
"sanitizedName": "richardbrucewright",
128+
"books": [
129+
{
130+
"_id": "0002005018",
131+
"title": "Clara Callan: A novel",
132+
"authors": [
133+
{
134+
"_id": {
135+
"$oid": "64cc2db4830ba29148da4c3b"
136+
},
137+
"name": "Richard Bruce Wright"
138+
}
139+
],
140+
"genres": [
141+
"Women Teachers",
142+
"Young Women",
143+
"Actresses",
144+
"Sisters"
145+
],
146+
"pages": 414,
147+
"year": 2001,
148+
"synopsis": "Giller Prize Winner 2001. Richard B. Wright. A Phyllis Bruce Book.",
149+
"cover": "https://images.isbndb.com/covers/50/12/9780002005012.jpg",
150+
"attributes": [
151+
{
152+
"key": "edition",
153+
"value": "1st"
154+
},
155+
{
156+
"key": "dimensions",
157+
"value": "Height: 11.11 Inches, Length: 6.11 Inches, Weight: 1 Pounds, Width: 1.11 Inches"
158+
},
159+
{
160+
"key": "isbn13",
161+
"value": "9780002005012"
162+
},
163+
{
164+
"key": "msrp",
165+
"value": "0.00"
166+
},
167+
{
168+
"key": "isbn",
169+
"value": "0002005018"
170+
},
171+
{
172+
"key": "isbn10",
173+
"value": "0002005018"
174+
}
175+
],
176+
"totalInventory": 2,
177+
"available": 3,
178+
"binding": "Hardcover",
179+
"language": "en",
180+
"publisher": "HarperFlamingoCanada",
181+
"longTitle": "Clara Callan: A novel",
182+
"reviews": [
183+
{
184+
"_id": {
185+
"$oid": "678900bc99a40f049f32d0be"
186+
},
187+
"text": "bbb",
188+
"name": "Tawdry Lemur",
189+
"rating": 5,
190+
"timestamp": 1737031868630
191+
},
192+
{
193+
"_id": {
194+
"$oid": "672231e138e1f3e7c1c1c1cf"
195+
},
196+
"text": "testss",
197+
"name": "Brash Iguana",
198+
"rating": 4,
199+
"timestamp": 1730294241948
200+
},
201+
{
202+
"_id": {
203+
"$oid": "6719acf4232c1a1deb2cbd7c"
204+
},
205+
"text": "hi",
206+
"name": "Brash Rhino",
207+
"rating": 5,
208+
"timestamp": 1729735924953
209+
},
210+
{
211+
"_id": {
212+
"$oid": "6719ace0232c1a1deb2cbd7b"
213+
},
214+
"text": "good",
215+
"name": "Killer Alligator",
216+
"rating": 3,
217+
"timestamp": 1729735904188
218+
},
219+
{
220+
"_id": {
221+
"$oid": "6719acdd232c1a1deb2cbd7a"
222+
},
223+
"text": "good",
224+
"name": "Killer Alligator",
225+
"rating": 5,
226+
"timestamp": 1729735901895
227+
}
228+
]
229+
}
230+
],
231+
"aliases": [
232+
"Wright, Richard Bruce"
233+
]
234+
}
235+
```
236+
237+
We can go ahead and remove the authors from the books array, as it is redundant:
238+
239+
```js
240+
[
241+
{$lookup: {
242+
from: "books",
243+
localField: "books",
244+
foreignField: "_id",
245+
as: "books"
246+
}
247+
},
248+
{$unset: 'books.authors'},
249+
]
250+
```
251+
252+
Now that our authors look the way we want, we can overwrite the authors collection using `$merge`
253+
254+
```js
255+
[
256+
{$lookup: {
257+
from: "books",
258+
localField: "books",
259+
foreignField: "_id",
260+
as: "books"
261+
}
262+
},
263+
{$unset: 'books.authors'},
264+
{$merge: {
265+
into: 'authors',
266+
on: '_id',
267+
whenMatched: 'replace',
268+
}}
269+
]
270+
```
271+
272+
- we use the `_id` field to match documents
273+
- we replace the existing ones with `replace`
274+
275+
:::warning
276+
We should see a message telling us that the $merge operator will cause the pipeline to persist the results to the specified location. This stage changes data.
277+
:::

0 commit comments

Comments
 (0)