馃憪 Searching inside Objects in arrays
In our books, we're using the Attribute Pattern to have different attributes in our documents. As we can see in the sample doc, we have an attributes
array, containing several objects, each with the same structure:
attributes: [
{
key: 'edition',
value: '1st'
},
{
key: 'dimensions',
value: 'Height: 1.111 Inches, Length: 1.111 Inches, Weight: 0.2 Pounds, Width: 1.111 Inches'
},
{
key: 'isbn13',
value: '9780765342508'
},
{
key: 'msrp',
value: 6.99
},
{
key: 'isbn',
value: '0765342502'
},
{
key: 'isbn10',
value: '0765342502'
}
],
How do we search for all the books that have an msrp of 9.99? We want books that, inside attributes
, have an object with key msrp
and value 9.99
. We can get it to work with this:
- Atlas UI
- MongoDB Shell
[
{ $unwind : "$attributes" },
{ $match: {"attributes.key": "msrp", "attributes.value": 9.99} },
{ $project: {title: 1, attributes: 1} }
]
db.books.aggregate([
{ $unwind : "$attributes" },
{ $match: {"attributes.key": "msrp", "attributes.value": 9.99} },
{ $project: {title: 1, attributes: 1} }
]);
Here we're getting a copy of each book for each object inside the $attributes
array. This "flattens" the array and returns many copies of the same documents, one for each different attribute that we have which will be different for each of these generated docs.
馃憪 To better understand $unwind
, run this aggregation.
- Atlas UI
- MongoDB Shell
You need to select the books
collection.
[
{ $match: {_id: "0395623650"} },
{ $unwind : "$attributes" },
]
db.books.aggregate([
{ $match: {_id: "0395623650"} },
{ $unwind : "$attributes" },
]);
You should get one document per attribute of the original book. All fields in these returned documents should be the same, except the ones in attributes.
But you can actually match documents in an array in a more straightforward fashion:
- Atlas UI
- MongoDB Shell
[
{ $match: {"attributes.key": "msrp", "attributes.value": 9.99} },
{ $project: {_id: 0, title: 1, year: 1, totalInventory: 1, available: 1, "attributes": 1} }
]
let nineNinetyNine = { $match: {"attributes.key": "msrp", "attributes.value": 9.99} };
let showOnlyTheseFields = { $project: {_id: 0, title: 1, year: 1, totalInventory: 1, available: 1, "attributes": 1} };
db.books.aggregate([
nineNinetyNine,
showOnlyTheseFields,
]);