Expand Contained Mongo Document - mongodb

This is for MongoDB
I have a Document say Employee as below:
{
"_id":"e01",
"name":"Andy",
"salary":"10000",
"address":"ad01id"
}
That is a simple Employee Document, with address being a foreign key to Address Document as below(for this above Employee)
{
"_id": "ad01id",
"pin":"999",
"Home":{
"street":"101",
"city":"someCity"
},
"Country":"someCountry"
}
I need a help to write a query which will fetch an Employee but will give me an output, which will have Employee's address field expanded with its entire document as
{
"_id":"e01",
"name":"Andy",
"salary":"10000",
"address":{
"pin":"999",
"Home":{
"street":"101",
"city":"someCity"
},
"Country":"someCountry"
}
}
I have tried $lookup and $merge but could not get the desired output - $merge hides the keys in the early document if the later document has the same key, which is the case in my real scenario. My actual documents have some keys with the same name. Such as name is there in both of my actual Documents.
Thanks in advance!

$lookup is needed to "join" the data from both collections and $unwind or $arrayElemAt can be used to convert an array being a result of $lookup into nested subdocument:
db.Employee.aggregate([
{
$lookup: {
from: "Address",
localField: "address",
foreignField: "_id",
as: "address"
}
},
{
$addFields: {
address: { $arrayElemAt: [ "$address", 0 ] }
}
},
{
$project: {
"address._id": 0
}
}
])
Mongo Playground

You can also use populate.
db.Employee.find(
{
},
)
.populate("address", "pin Home Country")
.exec(function(err, result) {
console.log(result)
});

Related

MongoDB: aggregation $lookup with lossy data type

I have two collections:
cats
balls
"cats" collection has documents with key "ballId" of type string
"balls" collection has documents with key "_id" of type ObjectId
An $lookup inside an aggregation is able to retrieve results if the join is done on keys with the same data type. However in my case, "ballId" and "_id" are of different types. This code retrieves the cats but doesn't retrieve the related balls:
collection('cats').aggregate([
{ $match:{} },
{
$lookup: {
from: "balls",
localField: "ballId",
foreignField: "_id",
as: "balls"
}
}
]);
How can I use $lookup with lossy data type?
Use $lookup with pipeline stage.
Join both collections by converting balls' _id to string ($toString) and next compare both values as string ($eq).
db.cats.aggregate([
{
$match: {}
},
{
$lookup: {
from: "balls",
let: {
ballId: "$ballId"
},
pipeline: [
{
$match: {
$expr: {
$eq: [
{
"$toString": "$_id"
},
"$$ballId"
]
},
}
}
],
as: "balls"
}
}
])
Sample Mongo Playground

How to make a query in two different collections in mongoDB? (without using ORM)

Suppose, In MongoDB i have two collections. one is "Students" and the another is "Course".
Student have the document such as
{"id":"1","name":"Alex"},..
and Course has the document such as
{"course_id":"111","course_name":"React"},..
and there is a third collection named "students-courses" where i have kept student's id with their corresponding course id. Like this
{"student_id":"1","course_id":"111"}
i want to make a query with student's id so that it gives the output with his/her enrolled course. like this
{
"id": "1",
"name":"Alex",
"taken_courses": [
{"course_id":"111","course_name":"React"},
{"course_id":"112","course_name":"Vue"}
]
}
it will be many to many relationship in MongoDB without using ORM. How can i make this query?
Need to use $loopup with pipeline,
First $group by student_id because we are going to get courses of students, $push all course_id in course_ids for next step - lookup purpose
db.StudentCourses.aggregate([
{
$group: {
_id: "$student_id",
course_ids: {
$push: "$course_id"
}
}
},
$lookup with Student Collection and get the student details in student
$unwind student because its an array and we need only one from group of same student record
$project required fields
{
$lookup: {
from: "Student",
localField: "_id",
foreignField: "id",
as: "student"
}
},
{
$unwind: "$student"
},
{
$project: {
id: "$_id",
name: "$student.name",
course_ids: 1
}
},
$lookup Course Collection and get all courses that contains course_ids, that we have prepared in above $group
$project the required fields
course details will store in taken_courses
{
$lookup: {
from: "Course",
let: {
cId: "$course_ids"
},
pipeline: [
{
$match: {
$expr: {
$in: [
"$course_id",
"$$cId"
]
}
}
},
{
$project: {
_id: 0
}
}
],
as: "taken_courses"
}
},
$project details, removed not required fields
{
$project: {
_id: 0,
course_ids: 0
}
}
])
Working Playground: https://mongoplayground.net/p/FMZgkyKHPEe
For more details related syntax and usage, check aggregation

MongoDB Compass: How can I perform a SQL join / Mongoose populate?

I have a collection called Post, which has an ID field called makeupProduct. This ID field is a foreign key to my MakeupProduct collection.
In MongoDB Compass, I'm trying to find all Posts
where productUrl === null and
populate the Makeup record along with it
Is this possible?
I have the 1st filter down, but don't know how to write the rest.
db.Post.aggregate([
{
$match: {
productUrl: null
}
},
{
$lookup:
{
from: "MakeupProduct",
localField: "makeupProduct",
foreignField: "_id",
as: "makeupProduct"
}
},
{
$set: {
makeupProduct: {
$arrayElemAt: ["$makeupProduct", 0]
}
}
}
])

MongoDB aggregate $lookup to return unmatched items from the main collection

I would like unmatched data from the USERS collection. Here I have two collections 1) USERS, 2) COMPANY.I am able to get the matched data from both USERS using aggregate function. but in this case I want data from USERS table which are not assigned to a company.
USERS table
{
_id: "AAA",
fullName:"John Papa"
},
{
_id: "BBB",
fullName:"Robin Son"
}
COMPANY table
{
_id: "1sd1s",
Name:"Lumbar Company"
User:"AAA"
},
{
_id: "23s1dfs3",
Name:"Patricia"
User:"AAA"
}
$lookup works like LEFT OUTER JOIN so it will remove empty array when there's no match. Then you can use $size to get only empty arrays:
db.users.aggregate([
{
$lookup: {
from: "company",
localField: "_id",
foreignField: "User",
as: "companies"
}
},
{
$match: {
$expr: {
$eq: [ { "$size": "$companies" }, 0 ]
}
}
}
])
Mongo Playground

MongoDB: Conditional select from one collection based on another collection

I'm fairly new to MongoDB and need help doing a select, or perhaps some sort of left join, on one collection based on another collection's data.
I have two collections, animals and meals, and I want to get the animal(s) that has had it's last registered meal after a certain date (let's say 20171001) to determine if the animal is still active.
collection animals:
{
name: mr floof,
id: 12345,
lastMeal: abcdef
},
{
name: pluto,
id: 6789,
lastMeal: ghijkl
}
collection meals:
{
id: abcdef,
created: 20171008,
name: carrots
},
{
id: ghijkl,
created: 20170918,
name: lettuce
}
So the expected output of the query in this case would be:
{
name: mr floof,
id: 12345,
lastMeal: abcdef
}
As Mr Floof has had his last meal 20171008, i.e. after 20171001.
Hope I was clear enough, but if not, don't hesitate to ask.
You can try below aggregation query.
db.animals.aggregate([ [
{
"$lookup": {
"from": "meals",
"localField": "lastMeal",
"foreignField": "id",
"as": "last_meal"
}
},
{
"$unwind": "$last_meal"
},
{
"$match": {
"last_meal.created": {
"$gt": 20171001
}
}
}
])
More info here.
You can use $project with exclusion after $match stage to format the response to exclude joined fields. Something like { $project: {"last_meal":0} }
MongoDB supports joins with $lookup , In your case you can use query like:-
db.animals.aggregate([
{
$lookup:
{
from: "meals",
localField: "lastMeal",
foreignField: "id",
as: "last_meal"
}
},
{
$match: {
"created" : {
$gt: "date" //your date format
}
}
}
])
thanks !