Related
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" }
}}
])
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"
}}
])
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"
}}
])
I have a question in MongoDB query.
I have the following users collection:
{
"_id" : ObjectId("5aa03bf97d6e1d28a020f488"),
"name":"A1",
"interests" : [
ObjectId("5aa03b877d6e1d28a020f484"),
ObjectId("5aa03bb47d6e1d28a020f485")
]
},
{
"_id" : ObjectId("5affd69339f67335303ddf77"),
"name":"A2",
"interests" : [
ObjectId("5aa03b877d6e1d28a020f484")
]
},
{
"_id" : ObjectId("5affd69339f673ddfjfhri45"),
"name":"A3",
"interests" : [
ObjectId("5aa03bb47d6e1d28a020f485"),
]
},
{
"_id" : ObjectId("5affd69339f67365656ddfg4f"),
"name":"A4",
"interests" : [
ObjectId("5aa16eb8890cbb4c582e8a38"),
]
}
The interests collection look li the following example:
{
"_id" : ObjectId("5aa16eb8890cbb4c582e8a38"),
"name" : "Swimming",
},
{
"_id" : ObjectId("5aa03bb47d6e1d28a020f485"),
"name" : "Basketball",
},
{
"_id" : ObjectId("5aa03b877d6e1d28a020f484"),
"name" : "Fishing",
}
I want to write a query that counts for the interests types of all users:
the expected result is like:
[
{
"name":"fishing"
"count":21
},
{
"name":"Basketball"
"count":15
}
]
Thanks for helpers :)
If you have mongodb 3.6 then you can try below aggregation
db.collection.aggregate([
{ "$lookup": {
"from": Intrest.collection.name,
"let": { "interests": "$interests" },
"pipeline": [
{ "$match": {
"$expr": { "$in": [ "$_id", "$$interests" ] },
"name": "Swimming",
}}
],
"as": "interests"
}},
{ "$unwind": "$interests" },
{ "$group": {
"_id": "$interests.name",
"count": { "$sum": 1 }
}},
{ "$project": {
"name": "$_id", "count": 1
}}
])
And if you want to group with interests name
db.collection.aggregate([
{ "$lookup": {
"from": Intrest.collection.name,
"let": { "interests": "$interests" },
"pipeline": [
{ "$match": { "$expr": { "$in": [ "$_id", "$$interests" ] } }}
],
"as": "interests"
}},
{ "$unwind": "$interests" },
{ "$group": {
"_id": "$interests.name",
"count": { "$sum": 1 }
}},
{ "$project": {
"name": "$_id", "count": 1
}}
])
db.collection.aggregate(
{
$group: {
_id: '$interests'
}
},
{
$group: {
_id: '$name',
count: {
$sum: 1
}
}
}
)
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"
}
}
}}
])