Select a nested document
This guide will show you how to select and return nested documents directly.
This is a common use case that one can face when working with a collection where relations are materialized by embedded documents.
We will use the listingsAndReviews
collection from the sample_airbnb
database.
This collection represents AirBnB listings.
The reviews
do not have their own collection, they are embedded in a reviews
field in the listingsAndReviews
collection.
What Do We Want to Achieve ?
We want to select all the reviews of a given reviewer.
How ?
This can be achieved by combining three stages:
$unwind
to deconstruct thereviews
array$replaceRoot
to promote thereviews
field to the root of the document$match
to select the documents that match the given reviewer
Thus the following pipeline will return all the reviews of the reviewer with the reviewer_id:2961855
:
# /!\ /!\ /!\
# Imports
# and boilerplate code
# to get the db object
# are not included
# /!\ /!\ /!\
# The reviewer_id whose reviews we want to retrieve
reviewer_id = "2961855"
# Building the pipeline
pipeline = Pipeline()
pipeline.unwind(
"reviews"
).replace_root(
"reviews"
).match(
reviewer_id=reviewer_id
)
# Executing the pipeline
cursor = db["listingsAndReviews"].aggregate(pipeline=pipeline.export())
documents = list(cursor)
documents[0]
should output:
{
'_id': '197072826',
'date': datetime.datetime(2017, 9, 24, 4, 0),
'listing_id': '18776184',
'reviewer_id': '2961855',
'reviewer_name': 'Uge',
'comments': 'Our stay at Alfredo’s place was amazing. \n\nThe place is spacious, very clean, comfortable, decorated with good taste, and has everything one may need. I really liked his apartment. \n\nIt is very well located, the restaurants and bars around are great and in an easy 30 minute walk you are downtown or in old Montreal. Very pleasant area to be outside and felt very safe. \n\nAlfredo always answered my messages within 5 minutes and was incredibly helpful and generous. \n\nI highly recommend this place. Thank you Alfredo!'
}
Generalization
This section aims at helping you adapt the above example to your own use case.
First, the unwind
stage above is not required in case of a one-to-one embedding relation.
For example, each listing has an address
field that contains the address of the listing. In this case, you can directly use the address
field in the replace_root
stage.
You do not need an unwind
stage there because the address
field is not an array.
Second, the documents could be more deeply nested. In that case, you would need to repeat the above steps for each level of nesting.