|
1 | 1 | # Lookupups AKA Left Outer Join
|
2 | 2 |
|
| 3 | +Using Documents we usually model 1:1, 1:many relationships embedding documents inside other documents, even using arrays for that. For instance an Author can have many aliases, and they live inside an array in the `authors` collection. |
| 4 | + |
| 5 | +But other times we need to use references to those documents instead of embedding them. For instance an author has an array of the books she has written, but instead of moving the book documents inside an array inside author (which will be tricky for books with multiple authors) we embed the books `_id` instead. |
| 6 | + |
| 7 | +So how can we get the authors and all the books she has written, embedded in the array? Using `$lookup`, that will do a Left Outer Join and return author docs containing book docs inside. |
| 8 | + |
| 9 | +💻 Run this aggregation and look at the results: |
| 10 | + |
| 11 | +```js |
| 12 | +db.authors.aggregate([ |
| 13 | + {$lookup: { |
| 14 | + from: "books", |
| 15 | + localField: "books", |
| 16 | + foreignField: "_id", |
| 17 | + as: "booksWritten" |
| 18 | + } |
| 19 | + }, |
| 20 | + {$project: {vectorizedSynopsis: 0, _id: 0}} |
| 21 | +]) |
| 22 | +``` |
| 23 | + |
| 24 | +The syntax for this version of `$lookup` is: |
| 25 | + |
| 26 | +```js |
| 27 | +{ |
| 28 | + $lookup: |
| 29 | + { |
| 30 | + from: <collection to join>, |
| 31 | + localField: <field from the input documents>, |
| 32 | + foreignField: <field from the documents of the "from" collection>, |
| 33 | + as: <output array field> |
| 34 | + } |
| 35 | +} |
| 36 | +``` |
| 37 | + |
| 38 | +## Lookups from a previous stage |
| 39 | + |
| 40 | +We can do a $lookup on the result of another pipeline, not only joining with a collection. For instance, we want to remove some noise from the books before joining, so we use `$project` to exclude a couple arrays. |
| 41 | + |
3 | 42 | ```js
|
4 | 43 | db.authors.aggregate([
|
5 |
| - { $unwind : "$books" }, |
6 | 44 | {$lookup: {
|
7 | 45 | from: "books",
|
8 | 46 | localField: "books",
|
9 | 47 | foreignField: "_id",
|
| 48 | + pipeline: [ |
| 49 | + {$project: {title: 1, synopsis: 1}} |
| 50 | + ], |
10 | 51 | as: "booksWritten"
|
11 | 52 | }
|
12 | 53 | }
|
13 | 54 | ])
|
14 | 55 | ```
|
15 | 56 |
|
| 57 | +The nice part is that we can extract that pipeline and test it / tweak it. |
| 58 | + |
16 | 59 | ```js
|
| 60 | +let booksFrom1996 = [ |
| 61 | + {$match: {year: 1996}}, |
| 62 | + {$project: {title: 1, synopsis: 1}}, |
| 63 | +] |
| 64 | + |
17 | 65 | db.authors.aggregate([
|
18 | 66 | {$lookup: {
|
19 | 67 | from: "books",
|
20 | 68 | localField: "books",
|
21 | 69 | foreignField: "_id",
|
| 70 | + pipeline: |
| 71 | + booksFrom1996, |
22 | 72 | as: "booksWritten"
|
23 | 73 | }
|
24 |
| - }, |
25 |
| - {$project: {vectorizedSynopsis: 0, _id: 0}} |
| 74 | + } |
26 | 75 | ])
|
27 |
| -``` |
| 76 | +``` |
| 77 | + |
0 commit comments