How to join multiple tables in mongodb - mongodb

I currently have 5 tables that need to joined due to their coupling.
Using $lookup I can join the Order table with the Plan table and get what I need, but how do I go about the other tables?
Here is each table, and the Id/table it needs to connect with
Plan - _id, unassignedOrderIds(array)
DriverPlan - _id, planId, orderIds(array), driverId, vehicleId
Driver - _id, vehicleId
Vehicle - _id
Orders - _id
In the end I'm looking for mongoDb to return a Plan object that has UnassignedOrders loaded and DriverPlans loaded. Followed by DriverPlans having its Orders,Driver, and Vehicle loaded.
Here is what I have so far:
db.Plan.aggregate([
// Unwind the source
{ "$unwind": "$UnassignedOrderIds" },
// Do the lookup matching
{ "$lookup": {
"from": "Order",
"localField": "UnassignedOrderIds",
"foreignField": "_id",
"as": "UnassignedOrders"
}},
// Unwind the result arrays ( likely one or none )
{ "$unwind": "$UnassignedOrders" },
// Group back to arrays
{ "$group": {
"_id": "$_id",
"Order": { "$push": "$Order" },
"UnassignedOrders": { "$push": "$UnassignedOrders" }
}}
])
Sample Document:
//Plan
{
"_id" : ObjectId("5c1d244de707b20cece645f1"),
"UnassignedOrderIds" : [
ObjectId("5c1d247fe707b20cece6462e"),
ObjectId("5c1d035de707b20cece63104")
]
}
//DriverPlan
[{
"_id" : ObjectId("123d247fe707b20cece6462e"),
"PlanId" : ObjectId("5c1d244de707b20cece645f1"),
"DriverId" : ObjectId("1c1d247fe707b20cece64622"),
"VehicleId" : ObjectId("3c1d247fe707b20cece64633"),
"OrderIds": [
ObjectId("5c1d247fe707b20cece64621"),
ObjectId("5c1d247fe707b20cece64624")
]
},{
"_id" : ObjectId("123d247fe707b20cece64655"),
"PlanId" : ObjectId("5c1d244de707b20cece645f1"),
"DriverId" : ObjectId("2c1d035de707b20cece63104"),
"VehicleId" : null,
"OrderIds": [
ObjectId("5c1d247fe707b20cece64625")
]
}]
//Orders
[{
"_id" : ObjectId("5c1d247fe707b20cece6462e"),
"name" "Order1"
},{
"_id" : ObjectId("5c1d035de707b20cece63104"),
"name" "Order2"
},{
"_id" : ObjectId("5c1d247fe707b20cece64621"),
"name" "Order3"
},{
"_id" : ObjectId("5c1d247fe707b20cece64624"),
"name" "Order4"
},{
"_id" : ObjectId("5c1d247fe707b20cece64625"),
"name" "Order5"
}]
//Driver
[{
"_id" : ObjectId("1c1d247fe707b20cece64622"),
"vehicleId" : ObjectId("3c1d247fe707b20cece6462e"),
"name" "Driver1"
},{
"_id" : ObjectId("2c1d035de707b20cece63104"),
"vehicleId" : null,
"name" "Driver2"
},{
"_id" : ObjectId("3c1d247fe707b20cece64621"),
"vehicleId" : ObjectId("3c1d035de707b20cece63104"),
"name" "Driver3"
}]
//Vehicle
[{
"_id" : ObjectId("3c1d247fe707b20cece6462e"),
"name" "Vehicle1"
},{
"_id" : ObjectId("3c1d035de707b20cece63104"),
"name" "Vehicle2"
},{
"_id" : ObjectId("3c1d247fe707b20cece64633"),
"name" "Vehicle3"
}]
The Expected output is json object as follows
//Plan with children loaded
{
"_id" : ObjectId("5c1d244de707b20cece645f1"),
"UnassignedOrderIds" : [
ObjectId("5c1d247fe707b20cece6462e"),
ObjectId("5c1d035de707b20cece63104")
],
"UnassignedOrders": [{
"_id" : ObjectId("5c1d247fe707b20cece6462e"),
"name" "Order1"
},{
"_id" : ObjectId("5c1d035de707b20cece63104"),
"name" "Order2"
}],
"DriverPlans" :
[{
"_id" : ObjectId("123d247fe707b20cece6462e"),
"PlanId" : ObjectId("5c1d244de707b20cece645f1"),
"DriverId" : ObjectId("1c1d247fe707b20cece64622"),
"Driver": {
"_id" : ObjectId("1c1d247fe707b20cece64622"),
"vehicleId" : ObjectId("3c1d247fe707b20cece6462e"),
"name" "Driver1"
},
"VehicleId" : ObjectId("3c1d247fe707b20cece64633"),
"Vehicle" : {
"_id" : ObjectId("3c1d247fe707b20cece64633"),
"name" "Vehicle3"
},
"OrderIds": [
ObjectId("5c1d247fe707b20cece64621"),
ObjectId("5c1d247fe707b20cece64624")
],
"Orders" : [
{
"_id" : ObjectId("5c1d247fe707b20cece64621"),
"name" "Order3"
},{
"_id" : ObjectId("5c1d247fe707b20cece64624"),
"name" "Order4"
}]
},{
"_id" : ObjectId("123d247fe707b20cece64655"),
"PlanId" : ObjectId("5c1d244de707b20cece645f1"),
"DriverId" : ObjectId("2c1d035de707b20cece63104"),
"Driver" : {
"_id" : ObjectId("2c1d035de707b20cece63104"),
"vehicleId" : null,
"name" "Driver2"
}
"VehicleId" : null,
"Vehicle" : null,
"OrderIds": [
ObjectId("5c1d247fe707b20cece64625")
],
"Orders": [{
"_id" : ObjectId("5c1d247fe707b20cece64625"),
"name" "Order5"
}
]
}]
}

You can use below aggregation
db.Plan.aggregate([
{ "$lookup": {
"from": Order.collection.name,
"let": { "unassignedOrderIds": "$UnassignedOrderIds" },
"pipeline": [
{ "$match": { "$expr": { "$in": ["$_id", "$$unassignedOrderIds"] } } }
],
"as": "UnassignedOrderIds"
}},
{ "$lookup": {
"from": DriverPlan.collection.name,
"let": { "planId": "$_id" },
"pipeline": [
{ "$match": { "$expr": { "$eq": ["$PlanId", "$$planId"] } } },
{ "$lookup": {
"from": Driver.collection.name,
"let": { "driveId": "$DriverId" },
"pipeline": [
{ "$match": { "$expr": { "$eq": ["$_id", "$$driveId"] } } }
],
"as": "Driver"
}},
{ "$lookup": {
"from": Vehicle.collection.name,
"let": { "vehicleId": "$VehicleId" },
"pipeline": [
{ "$match": { "$expr": { "$eq": ["$_id", "$$vehicleId"] } } }
],
"as": "Vehicle"
}},
{ "$lookup": {
"from": Order.collection.name,
"let": { "orderIds": "$OrderIds" },
"pipeline": [
{ "$match": { "$expr": { "$in": ["$_id", "$$orderIds"] } } }
],
"as": "Orders"
}}
],
"as": "DriverPlans"
}}
])
With mongodb 3.4 and below $lookup syntax
db.Plan.aggregate([
{ "$lookup": {
"from": Order.collection.name,
"localField": "UnassignedOrderIds",
"foreignField": "_id",
"as": "UnassignedOrderIds"
}},
{ "$lookup": {
"from": DriverPlan.collection.name,
"localField": "_id",
"foreignField": "PlanId",
"as": "DriverPlans"
}},
{ "$unwind": "$DriverPlans" },
{ "$lookup": {
"from": Driver.collection.name,
"localField": "DriverPlans.DriverId",
"foreignField": "_id",
"as": "DriverPlans.Driver"
}},
{ "$unwind": "$DriverPlans.Driver" },
{ "$lookup": {
"from": Vehicle.collection.name,
"localField": "DriverPlans.VehicleId",
"foreignField": "_id",
"as": "DriverPlans.Vehicle"
}},
{ "$unwind": "$DriverPlans.Vehicle" },
{ "$lookup": {
"from": Order.collection.name,
"localField": "DriverPlans.OrderIds",
"foreignField": "_id",
"as": "DriverPlans.Orders"
}},
{ "$group": {
"_id": "$_id",
"DriverPlans": { "$push": "$DriverPlans" }
}}
])

Related

How to aggregate array of ObjectId pairs with their relevant collection

I have a course collection in which I am allotting teachers for each subject of that course. The allotment is saved as an array of JSON please take a look at the reference doc below.
{
"_id" : ObjectId("5cc7d72d8e165005cbef939e"),
"isAssigned" : true,
"name" : "11",
"section" : "A",
"allotment" : [
{
"subject" : ObjectId("5cc3f7cc88e95a0c8e8ccd7d"),
"teacher" : ObjectId("5cbee0e37a3c852868ec9797")
},
{
"subject" : ObjectId("5cc3f80e88e95a0c8e8ccd7e"),
"teacher" : ObjectId("5cbee10c7a3c852868ec9798")
}
]
}
I am trying to match the subject and teacher fields along with their doc from two different collections. I could get them in two different array's but couldn't get them as structured in my expected output
Doc in teachers collection
{
_id: ObjectId("5cbee0e37a3c852868ec9797"),
name: "Alister"
}
Doc in subject
{
_id: ObjectId("5cc3f7cc88e95a0c8e8ccd7d"),
name: "English",
code: "EN"
}
Query I tried
Course.aggregate([
{"$match": matchQuery},
{"$lookup": {
"from": "subjects",
"localField": "allotment.subject",
"foreignField": "_id",
"as": "subjectInfo"
}
},
{"$lookup": {
"from": "teachers",
"localField": "allotment.teacher",
"foreignField": "_id",
"as": "teacherInfo"}
},
])
Output of that Query
{
isAssigned: true
name: "11"
section: "A"
subjectInfo:[
{_id: "5cc3f7cc88e95a0c8e8ccd7d", name:"English", code:"EN"}
{_id: "5cc3f80e88e95a0c8e8ccd7e", name: "Science", code:"SC"}
]
teacherInfo:[
{_id: ObjectId("5cbee0e37a3c852868ec9797"),name: "Alister"},
{ _id: ObjectId("5cbee10c7a3c852868ec9798"),name: "Frank"}
]
}
Expexted output
{
"_id" : ObjectId("5cc7d72d8e165005cbef939e"),
"isAssigned" : true,
"name" : "11",
"section" : "A",
"allotment" : [
{
"subject" : {
_id: ObjectId("5cc3f7cc88e95a0c8e8ccd7d"),
name: "English",
code: "EN"
}
"teacher" : {
_id: ObjectId("5cbee0e37a3c852868ec9797"),
name: "Alister"
}
},
{
"subject" : {
_id: ObjectId("5cc3f80e88e95a0c8e8ccd7e"),
name: "Science",
code: "SC"
}
"teacher" : {
_id: ObjectId("5cbee10c7a3c852868ec9798"),
name: "Frank"
}
}
]
}
Just unwind the array before the lookups:
Course.aggregate([
{"$match": matchQuery},
{"$unwind: "$allotment"}
{"$lookup": {
"from": "subjects",
"localField": "allotment.subject",
"foreignField": "_id",
"as": "subjectInfo"
}
},
{"$lookup": {
"from": "teachers",
"localField": "allotment.teacher",
"foreignField": "_id",
"as": "teacherInfo"}
},
])
if you want to re-group after that to restore expected format you can add:
{ $group : {
_id: "$_id",
name: {$first: "$name"},
section: {$first: "$section},
isAssigned: {$first: "$isAssigned},
allotment: {$push: {teacher: "$teacherInfo.0", subject: "$subjectInfo.0"}}
I'm assuming teacherInfo and subjectInfo are never empty, if this is not the case you should add a $match to filter empty ones.
Take a look at $lookup aggregation stage which lets you join collections. There's a plenty of examples on the usage in the documentation.
EDIT: Here's the complete pipeline that should provide the expected result:
courses.aggregate(
[
{
"$unwind" : {
"path" : "$allotment"
}
},
{
"$lookup" : {
"from" : "subjects",
"localField" : "allotment.subject",
"foreignField" : "_id",
"as" : "allotment.subject"
}
},
{
"$lookup" : {
"from" : "teachers",
"localField" : "allotment.teacher",
"foreignField" : "_id",
"as" : "allotment.teacher"
}
},
{
"$addFields" : {
"allotment.subject" : {
"$arrayElemAt" : [
"$allotment.subject",
0.0
]
},
"allotment.teacher" : {
"$arrayElemAt" : [
"$allotment.teacher",
0.0
]
}
}
},
{
"$group" : {
"_id" : "$_id",
"isAssigned" : {
"$first" : "$isAssigned"
},
"name" : {
"$first" : "$name"
},
"section" : {
"$first" : "$section"
},
"allotment" : {
"$addToSet" : "$allotment"
}
}
}
]
)
Firstly you have to $unwind the allotment array and then apply $lookup for subject and then repeat same for teachers and finally apply $group to combine back it inside array. See below aggregate query that is have tried and its working for me.
Course.aggregate([
{"$match": matchQuery},
{
$unwind: '$allotment'
},
{
$lookup:{
"from": "subjects",
"localField": "allotment.subject",
"foreignField": "_id",
"as": "allotment.subject"
}
},
{
$unwind: '$allotment.subject'
},
{
"$lookup": {
"from": "teachers",
"localField": "allotment.teacher",
"foreignField": "_id",
"as": "allotment.teacher"
}
},
{
$unwind: '$allotment.teacher'
},
{
"$group" : {
"_id" : "$_id",
"isAssigned" : {
"$first" : "$isAssigned"
},
"name" : {
"$first" : "$name"
},
"section" : {
"$first" : "$section"
},
"allotment" : {
"$addToSet" : "$allotment"
}
}
}
])

exclude fields in $lookup aggregation

I am querying between 3 collections I want to exclude _id everywhere in output
My output is:
{
"_id" : ObjectId("5b6aed5f9bcdb5d4ae64aef5"),
"userID" : "1",
"skills" : [
{
"_id" : ObjectId("5b766b5f1365a4940bb6050f"),
"skillID" : "javaid",
"skillname" : "जावा",
"languageID" : "hindiid"
},
{
"_id" : ObjectId("5b766b8c1365a4940bb60535"),
"skillID" : "pythonid",
"skillname" : "पायथन",
"languageID" : "hindiid"
}
],
"gender" : {
"_id" : ObjectId("5b7687cd2a2329043e2383d5"),
"genderID" : "femaleid",
"gendername" : "महिला",
"languageID" : "hindiid"
}
}
Query:
db.User.aggregate([
{ "$match": { "userID":"1" }},
{ "$lookup":{
"from": "Skill",
"pipeline": [
{ "$match": { "languageID": "hindiid", "skillID": { "$in": [ "javaid","pythonid" ] }}},
],
"as": "skills"
}},
{ "$lookup": {
"from": "Gender",
"pipeline": [
{ "$match": { "languageID": "hindiid", "genderID" : "femaleid" }},
],
"as": "gender"
}},
{ "$unwind": { "path": "$gender", "preserveNullAndEmptyArrays": true }},
{ "$project": { "userID": 1, "skills": 1, "gender": 1 }}
])
In output for every object has _id.Example for skill list every object has _id i want exclude _id field every where. How I can exclude?
In mongodb 3.6 you can use projection ($project) inside $lookup pipeline... Something like this
db.User.aggregate([
{ "$match": { "userID":"1" }},
{ "$lookup":{
"from": "Skill",
"pipeline": [
{ "$match": { "languageID": "hindiid", "skillID": { "$in": [ "javaid","pythonid" ] }}},
{ "$project": { "_id": 0 }}
],
"as": "skills"
}}
])

$lookup with nested data in mongodb

How do I combine 2 array objects using mongoDB NoSQL? Because I have tried to find some of the same problems here that I got, but I have not found the answers and problems that match what I got.
If someone here wants to help me, here are the problems I want to solve.
Example: I tried using noSQL in mongoDB like this:
db.tables.aggregate([
{ $lookup: { from: 'reservations', localField: '_id', foreignField: 'tableId', as: 'reservation' }},
{ $unwind: { path: '$reservation', 'preserveNullAndEmptyArrays': true }},
{ $lookup: { from: 'orders', localField: 'reservation._id', foreignField: 'reservationId', as: 'orders' }},
{ $lookup: { from: 'products', localField: 'orders.productId', foreignField: '_id', as: 'products' }},
{
$project: {
'_id': 1,
'initial': 1,
'description': 1,
'reservation._id': 1,
'reservation.guest': 1,
'orders._id': 1,
'orders.status': 1,
'orders.quantity': 1,
'orders.productId': 1,
'products._id': 1,
'products.name': 1
}
},
]);
After running noSQL mongoDB above, I got the results below:
{
"_id" : ObjectId("5b63e519514cf01c2864749a"),
"description" : "Kursi VIP 01",
"reservation" : {
"_id" : ObjectId("5b63f104514cf01c286474b6"),
"guest" : "Jhon Doe"
},
"orders" : [
{
"_id" : ObjectId("5b63f239514cf01c286474bb"),
"productId" : ObjectId("5b63e72d514cf01c286474a3"),
"status" : "3",
"quantity" : "2"
},
{
"_id" : ObjectId("5b63f252514cf01c286474bc"),
"productId" : ObjectId("5b63e7de514cf01c286474a6"),
"status" : "2",
"quantity" : "3"
},
{
"_id" : ObjectId("5b63f267514cf01c286474bd"),
"productId" : ObjectId("5b63e937514cf01c286474ac"),
"status" : "0",
"quantity" : "2"
}
],
"products" : [
{
"_id" : ObjectId("5b63e72d514cf01c286474a3"),
"name" : "AQUA 600ML"
},
{
"_id" : ObjectId("5b63e7de514cf01c286474a6"),
"name" : "Nasi Goreng Kecap Asin"
},
{
"_id" : ObjectId("5b63e937514cf01c286474ac"),
"name" : "Daging Ayam Goreng"
}
]
}
Now, my Question is. How to merge/combine 2 Object Array ("orders and products"), So I can get results like this:
{
"_id" : ObjectId("5b63e519514cf01c2864749a"),
"description" : "Kursi VIP 01",
"reservation" : {
"_id" : ObjectId("5b63f104514cf01c286474b6"),
"guest" : "Jhon Doe"
},
"orders" : [
{
"_id" : ObjectId("5b63f239514cf01c286474bb"),
"productId" : ObjectId("5b63e72d514cf01c286474a3"),
"name" : "AQUA 600ML",
"status" : "3",
"quantity" : "2"
},
{
"_id" : ObjectId("5b63f252514cf01c286474bc"),
"productId" : ObjectId("5b63e7de514cf01c286474a6"),
"name" : "Nasi Goreng Kecap Asin",
"status" : "2",
"quantity" : "3"
},
{
"_id" : ObjectId("5b63f267514cf01c286474bd"),
"productId" : ObjectId("5b63e937514cf01c286474ac"),
"name" : "Daging Ayam Goreng"
"status" : "0",
"quantity" : "2"
}
]
}
I hope, someone can help me.
Thanks in advance.
You can try below aggregation with mongodb 3.4
You need to $unwind the orders array to add the field($addFields) name inside orders and then $group to rollback orders again to the make an array field
db.tables.aggregate([
{ "$lookup": {
"from": "reservations",
"localField": "_id",
"foreignField": "tableId",
"as": "reservation"
}},
{ "$unwind": { "path": '$reservation', 'preserveNullAndEmptyArrays': true }},
{ "$lookup": {
"from": "orders",
"localField": "reservation._id",
"foreignField": "reservationId",
"as": "orders",
}},
{ "$unwind": { "path": '$orders', 'preserveNullAndEmptyArrays': true }},
{ "$lookup": {
"from": "products",
"localField": "orders.productId",
"foreignField": "_id",
"as": "orders.products"
}},
{ "$unwind": { "path": '$orders.products', 'preserveNullAndEmptyArrays': true }},
{ "$addFields": {
"orders.name": "$orders.products.name"
}},
{ "$group": {
"_id": "$_id",
"description": { "$first": "$description" },
"reservation": { "$first": "$reservation" },
"orders": { "$push": "$orders" }
}},
{ "$project": { "orders.products": 0 }}
])
Which is far simple with mongodb 3.6 nested $lookup version
db.tables.aggregate([
{ "$lookup": {
"from": "reservations",
"let": { "reservationId": "$_id" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$tableId", "$$reservationId" ] } } }
],
"as": "reservations"
}},
{ "$lookup": {
"from": "orders",
"let": { "reservationId": "$reservation._id" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$reservationId", "$$reservationId" ] } } },
{ "$lookup": {
"from": "products",
"let": { "productId": "$productId" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$_id", "$$productId" ] } } },
{ "$project": { "_id": false }}
],
"as": "products"
}},
{ "$unwind": "$products" },
{ "$addFields": { "name": "$products.name" } },
{ "$project": { "products": 0 }}
],
"as": "orders"
}}
])

MongoDB aggregation with multiple inter-related collections

I have the following collections;
users, user_roles, market_managers, program_markets, programs
I can export the data from mongoDB in CSV format and construct relational tables and run the following SQL statement to retrieve the data I need;
select u.name, ur.type, pm.code, p.program_name, p.shortnam, p.enddate, p.description
from users u, user_roles ur, market_managers mm, program_markets pm, programs p
where u.roles_0 = ur.id
and ur.type = 'CountryManager'
and u.id = mm.userid
and pm.programid = mm.programid
and pm.id = mm.marketid
and p.id = pm.programid;
How can I achieve the same results by writing native mongo syntax?
Here's a list of collections in scope:
users collection
{
"_id" : ObjectId("5b3f59c96e1c20d84e2b5ce5"),
"name" : "some_country_manager",
"roles" : [
"5b2a8df52b3a6f945d4e85fe"
]
}
user_roles collection
{
"_id" : ObjectId("5b430f9981f6a7382a24995b"),
"type" : "countryManager",
"name" : "Country Manager"
}
market_managers collection
{
"_id" : ObjectId("5894bcf60418700b70745fc9"),
"programId" : "5862c1d43b1a1b113a8a841f",
"marketId" : "5862c1d43b1a1b113a8a84a9",
"userId" : "5b3f59c96e1c20d84e2b5ce5"
}
program_markets collection
{
"_id" : ObjectId("5b43588689c117241c171e8c"),
"code" : "de",
"startDate" : "2018-07-09",
"endDate" : "2019-07-09"
}
programs collection
{
"_id" : ObjectId("5862c1d43b1a1b113a8a841f"),
"name" : "Test Program",
"shortname" : "TestP",
"status" : "planned",
"startDate" : "2018-07-09",
"endDate" : "2019-07-09",
"description" : "Test Program"
}
You can try below aggregation if you have mongodb 3.6 and above
Users.aggregate([
{ "$match": { "_id": mongoose.Types.ObjectId(id.id) } },
{ "$lookup": {
"from": UserRoles.collection.name,
"let": { "roles_0": "$roles_0" },
"pipeline": [
{ "$match": {
"$expr": { "$eq": [ "$_id", "$$roles_0" ] },
"type": "CountryManager"
}}
],
"as": "role"
}},
{ "$lookup": {
"from": MarketManagers.collection.name,
"let": { "user_id": "$_id" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$_id", "$$user_id" ] }}},
{ "$lookup": {
"from": Programs.collection.name,
"let": { "programid": "$programid" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$_id", "$$programid" ] }}}
],
"as": "programs"
}},
{ "$lookup": {
"from": ProgramManagers.collection.name,
"let": { "marketId": "$marketId" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$_id", "$$marketId" ] }}},
{ "$lookup": {
"from": Programs.collection.name,
"let": { "id": "$id" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$_id", "$$id" ] }}}
],
"as": "programs"
}}
],
"as": "programManagers"
}}
],
"as": "marketManagers"
}}
])

$lookup nested array in mongodb

I am struggling with the newish (lovely) lookup operator in MongoDB. I have 3 collections:
artists
{
"_id" : ObjectId("5b0d2b2c7ac4792df69a9942"),
"name" : "Dream Theater",
"started_in" : NumberInt(1985),
"active" : true,
"country" : "US",
"current_members" : [
ObjectId("5b0d2a7c7ac4792df69a9941")
],
"previous_members" : [
ObjectId("5b0d2bf57ac4792df69a9954")
],
"albums" : [
ObjectId("5b0d16ee7ac4792df69a9924"),
ObjectId("5b0d47667ac4792df69a9994")
],
"genres" : [
"prog metal",
"prog rock"
]
}
Albums
{
"_id" : ObjectId("5b0d16ee7ac4792df69a9924"),
"title" : "Images and words",
"released" : ISODate("1992-07-07T00:00:00.000+0000"),
"songs" : [
ObjectId("5b0d15ab7ac4792df69a9916"),
ObjectId("5b0d15ee7ac4792df69a991e"),
ObjectId("5b0d2db37ac4792df69a995d"),
ObjectId("5b0d2dbe7ac4792df69a995e"),
ObjectId("5b0d2dcb7ac4792df69a995f"),
ObjectId("5b0d2dd87ac4792df69a9960"),
ObjectId("5b0d2de27ac4792df69a9961"),
ObjectId("5b0d2dec7ac4792df69a9962")
],
"type" : "LP"
}
{
"title" : "Awake",
"released" : ISODate("1994-10-04T00:00:00.000+0000"),
"songs" : [
ObjectId("5b0d470d7ac4792df69a9991")
],
"type" : "LP",
"_id" : ObjectId("5b0d47667ac4792df69a9994")
}
Songs
{
"_id" : ObjectId("5b0d15ab7ac4792df69a9916"),
"title" : "Pull me under"
}
{
"_id" : ObjectId("5b0d15ee7ac4792df69a991e"),
"title" : "Another day"
}
{
"title" : "Take the time",
"_id" : ObjectId("5b0d2db37ac4792df69a995d")
}
{
"title" : "Surrounded",
"_id" : ObjectId("5b0d2dbe7ac4792df69a995e")
}
{
"title" : "Metropolis - part I",
"_id" : ObjectId("5b0d2dcb7ac4792df69a995f")
}
{
"title" : "Under a glass moon",
"_id" : ObjectId("5b0d2dd87ac4792df69a9960")
}
{
"title" : "Wait for sleep",
"_id" : ObjectId("5b0d2de27ac4792df69a9961")
}
{
"title" : "Learning to live",
"_id" : ObjectId("5b0d2dec7ac4792df69a9962")
}
{
"title" : "6:00",
"_id" : ObjectId("5b0d470d7ac4792df69a9991")
}
I can easily do an aggregation with $lookup to get the detailed albums array, but how do I get also the detailed songs in the corresponding albums?
I would like to extend the following query:
db.artists.aggregate([ {
$lookup: {
from: "albums",
localField: "albums",
foreignField: "_id",
as: "albums"
}
}]).pretty()
If you have mongodb version 3.6 then you can try with nested $lookup aggregation...
db.collection.aggregate([
{ "$lookup": {
"from": Albums.collection.name,
"let": { "albums": "$albums" },
"pipeline": [
{ "$match": { "$expr": { "$in": [ "$_id", "$$albums" ] } } },
{ "$lookup": {
"from": Songs.collection.name,
"let": { "songs": "$songs" },
"pipeline": [
{ "$match": { "$expr": { "$in": [ "$_id", "$$songs" ] } } }
],
"as": "songs"
}}
],
"as": "albums"
}}
])
And for long-winded explanation you can go through $lookup multiple levels without $unwind?
Or If you have mongodb version prior to 3.6
db.collection.aggregate([
{ "$lookup": {
"from": Albums.collection.name,
"localField": "albums",
"foreignField": "_id",
"as": "albums"
}},
{ "$unwind": "$albums" },
{ "$lookup": {
"from": Songs.collection.name,
"localField": "albums.songs",
"foreignField": "_id",
"as": "albums.songs",
}},
{ "$group": {
"_id": "$_id",
"name": { "$first": "$name" },
"started_in": { "$first": "$started_in" },
"active": { "$first": "$active" },
"country": { "$first": "$country" },
"albums": {
"$push": {
"_id": "$albums._id",
"title": "$albums.title",
"released": "$albums.released",
"type": "$albums.type",
"songs": "$albums.songs"
}
}
}}
])