So, I have two collections User and Book, and I want to aggregate them to receive an output (shown at the end of the post) for a specific User ID.
below are the collections:
User
Each document contains User ID
, Name
of the User and an array containing ID of a document from Book collection and a Boolean property read
.
[
{
_id: ObjectId('adfa2sd5'),
name: "Mia",
books: [
{
bid: "154854",
read: true
},
{
bid: "5475786",
read: false
}
]
},
{
_id: ObjectId('uai5as5a'),
name: "Jack",
books: [
{
bid: "5475786",
read: true
}
]
}
]
Book
Each document possesses a book ID
and name
of the book.
[
{
_id: ObjectId('154854'),
name: "The Great Gatsby"
},
{
_id: ObjectId('5475786'),
name: "Frankenstein"
},
]
Output:
The output contains the User ID
, along an array book_list
which contains detail of each book (id, name) from the documents of Book collection based on the books.bid
from User document and read
field which was along books.bid
.
[
{
_id: ObjectId('adfa2sd5'),
book_list: [
{
_id: ObjectId('154854'),
name: "The Great Gatsby",
read: true
},
{
_id: ObjectId('5475786'),
name: "Frankenstein",
read: false
}
]
}
]
Here's one way you could do it.
db.users.aggregate([
{
"$match": {
"_id": ObjectId("fedcba9876543210fedcba98")
}
},
{
"$lookup": {
"from": "books",
"localField": "books.bid",
"foreignField": "_id",
"as": "bookList"
}
},
{
"$set": {
"books": {
"$map": {
"input": "$books",
"as": "book",
"in": {
"$mergeObjects": [
"$$book",
{
"name": {
"$getField": {
"field": "name",
"input": {
"$first": {
"$filter": {
"input": "$bookList",
"cond": {"$eq": ["$$this._id", "$$book.bid"]}
}
}
}
}
}
}
]
}
}
}
}
},
{"$unset": ["bookList", "name"]}
])
Try it on mongoplayground.net.