I have a collection users as follows:
{ "_id" : ObjectId("570557d4094a4514fc1291d6"), "email": "[email protected]", "user_type" : "1", "grade" : "A1", "room_id" : ObjectId("580557d4094a4514fc1291d6") }
{ "_id" : ObjectId("570557d4094a4514fc1291d7"), "email": "[email protected]", "user_type" : "2", "grade" : "A2", "room_id" : ObjectId("580557d4094a4514fc1291d6") }
{ "_id" : ObjectId("570557d4094a4514fc1291d8"), "email": "[email protected]", "user_type" : "3", "grade" : "A2", "room_id" : ObjectId("580557d4094a4514fc1291d6") }
{ "_id" : ObjectId("570557d4094a4514fc1291d9"), "email": "[email protected]", "user_type" : "2", "grade" : "A2", "room_id" : ObjectId("580557d4094a4514fc1291d7") }
{ "_id" : ObjectId("570557d4094a4514fc1291e6"), "email": "[email protected]", "user_type" : "3", "grade" : "A1", "room_id" : ObjectId("580557d4094a4514fc1291d7") }
{ "_id" : ObjectId("570557d4094a4514fc1291e7"), "email": "[email protected]", "user_type" : "3", "grade" : "A2", "room_id" : ObjectId("580557d4094a4514fc1291d7") }
{ "_id" : ObjectId("570557d4094a4514fc1291e8"), "email": "[email protected]", "user_type" : "2", "grade" : "A1", "room_id" : ObjectId("580557d4094a4514fc1291d8") }
{ "_id" : ObjectId("570557d4094a4514fc1291e9"), "email": "[email protected]", "user_type" : "3", "grade" : "A1", "room_id" : ObjectId("580557d4094a4514fc1291d8") }
I want to find email ids of users of type 2 having grade A2, along with their roommates having the same room_id but user_type 3 (grade does not matter for roommates). So the result data should look like this:
{"email": "[email protected]", "roommates": [{"email": "[email protected]"}]}
{"email": "[email protected]", "roommates": [{"email": "[email protected]"}, {"email": "[email protected]"}]}
How do I do this in MongoDB? I have a background in SQL so I am thinking of a self join, but I guess there are other ways to do it.
CodePudding user response:
Yes, the (concept/direction) of self-join users collection is correct.
$lookup- Joinuserscollection byroom_idand returnroommatesarray.$match- Filter the document byuser_type,gradeandroommates.user_type.$project- Decorate the output document.3.1.
$map- Iterate theroommatesarray and returns an array.3.1.1.
$filter- Filter the document withuser_typeinroommatesarray.
db.users.aggregate([
{
$lookup: {
from: "users",
localField: "room_id",
foreignField: "room_id",
as: "roommates"
}
},
{
$match: {
user_type: "2",
grade: "A2",
"roommates.user_type": "3"
}
},
{
$project: {
email: 1,
roommates: {
$map: {
input: {
$filter: {
input: "$roommates",
cond: {
$eq: [
"$$this.user_type",
"3"
]
}
}
},
in: {
email: "$$this.email"
}
}
}
}
}
])
