this is the example of 'Routes' document
[{
routes: [{
driver_id: "61e9536f142f337c96883c52",
route_id:"SRT006",
payment:13.2
}, {
driver_id: "61e9536f142f337c96800a56",
route_id:"SRT005",
payment:15
}, {
route_id:"SRT004",
payment:20
}],
apartment: 'abc apartment',
deliverydate: "06/03/2022"
}]
this is the example of 'Users' document
[
{
_id: ObjectId(61e9536f142f337c96883c52),
name: 'John',
phone: (222) 123-4568
},
{
_id: ObjectId(61e9536f142f337c96800a56),
name: 'Bob',
phone: (200) 123-4568
}
]
Final results should be like this
[{
routes: [{
driver_id: "61e9536f142f337c96883c52",
driver_name: 'John',
route_id:"SRT006",
payment:13.2
}, {
driver_id: "61e9536f142f337c96800a56",
driver_name: 'Bob',
route_id:"SRT005",
payment:15
}, {
route_id:"SRT004",
payment:20
}],
apartment: 'abc apartment',
deliverydate: "06/03/2022"
}]
I have tried $lookup to add driver_name but getting errors. Any advice on what is the approach to getting the above results on MongoDB?
CodePudding user response:
$lookup
-routes
collection join withusers
collection via pipeline.1.1.
$in
- Filter the document with_id
(converted tostring
type) is inroutes_driver_id
array.1.2.
$project
- Decorate output document(s) to be returned in thedriver
array.$set
- Setroutes
field.2.1.
$map
- Iterate each element in theroutes
array and returns a new array.2.1.1.
$mergeObjects
- Merge current iterated document with the result 2.1.1.1.2.1.1.1.
$first
- Get the first value of the array from 2.1.1.1.1.2.1.1.1.1.
$filter
- Filter thedriver
document by matching currentroute
's_id
withdriver_id
(converted tostring
type).$unset
- Removedriver
field.
db.routes.aggregate([
{
"$lookup": {
"from": "users",
"as": "driver",
"let": {
routes_driver_id: "$routes.driver_id"
},
"pipeline": [
{
$match: {
$expr: {
$in: [
{
$toString: "$_id"
},
"$$routes_driver_id"
]
}
}
},
{
$project: {
_id: 0,
driver_id: "$_id",
name: 1
}
}
]
}
},
{
$set: {
routes: {
$map: {
input: "$routes",
as: "route",
in: {
$mergeObjects: [
"$$route",
{
$first: {
$filter: {
input: "$driver",
cond: {
$eq: [
"$$route.driver_id",
{
$toString: "$$this.driver_id"
}
]
}
}
}
}
]
}
}
}
}
},
{
$unset: "driver"
}
])
CodePudding user response:
The datatypes in your two collections are different, that's why it might be failing. driver_id
is a string within Routes
collection, but in users
it's an ObjectId
. Try this:
db.routes.aggregate([
{
"$unwind": "$routes"
},
{
"$lookup": {
"from": "users",
"localField": "routes.driver_id",
"foreignField": "_id",
"as": "driver"
}
},
{
"$addFields": {
"driver": {
"$arrayElemAt": [
"$driver",
0
]
}
}
},
{
"$addFields": {
"routes.driver_name": "$driver.name"
}
},
{
"$project": {
driver: 0
}
},
{
"$group": {
"_id": "$_id",
"routes": {
"$push": "$routes"
}
}
}
])
Here's the playground link. In this, we use ObjectId
, in both collections. We unwind the routes array, perform the lookup and then group again on the basis of _id
.