DEV Community

Cover image for How to use Populate in Mongoose & Node.js

How to use Populate in Mongoose & Node.js

Paras πŸ§™β€β™‚οΈ on September 07, 2020

While working on a MERN stack project, I came across a situation where I wanted to populate a field but also populate a field inside that populated...
Collapse
Β 
jwkicklighter profile image
Jordan Kicklighter β€’

From the outside, this seems like basically creating JOIN functionality from an RDBMS. That's not a bad thing! It turns out that sometimes an RDBMS needs document-style records, and sometimes document DBs need relations :) Just wanted to make the comparison in case it helps anyone else (and to make sure I understand it correctly).

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Correct !!...And Nice comparision. :)

Collapse
Β 
laygir profile image
Liger β€’

Mongo newbie here πŸ‘‹πŸ»
Is it possible to do findOne after the populate?

The query string I have available belongs to the referenced document. I would like to first populate it and then find the document I am looking for.

Other wise I first need to do a findOne in one collection and pass the result to another collection’s findOne.

I am trying to avoid an unnecessary findOne operation but maybe I am overthinking it and its okay to do multiple findOne’s to reach a result?

Another solution comes to my mind is to make the query string I have available an indexed unique field so I can directly do findOne.

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Great point you made there. I never tried that, but I guess you can give it try. For cases like these, I tend to use aggregation.

Collapse
Β 
daniel_la039905 profile image
Daniel-LA0303 β€’

Merci!!! m'a beaucoup aidΓ© cette information!! :)

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Je vous en price. 😊

Collapse
Β 
husainahar profile image
husain-nahar β€’

I have a schema named Product inside I have added another schema named Category. I want to get all the products related to a particular category(_id) passed. how do I do that. please help.

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

I think you can simply use find products and check for category using $in operator. If it doesn't help then can you show a dummy schema and what you want in result?

Collapse
Β 
khanhle81839451 profile image
Khanh Le β€’

Thank you for great article.
But I have a concern, what if I use my custom Id:string as a key, what will the type be rather than mongoose.Schema.Types.ObjectId?

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’ β€’ Edited

There is a concept called "Virtuals". I came across it when I was thinking the same thing. I can only give you hint about it because I have not learned or applied them. In virtuals, you define the conditions for virtuals: 'localField' and 'foreignField'. Local field refers to the name of the field of your current Schema. Foreign field is the name of the field which you are using in other schema to refer to your current Schema. Then you use populate normally.

// modal = Authors
const authorsSchema = {
  name: String,
  article: String 
}

// model = Articles
const articlesSchema = {
  title: String
}

authorsSchema.virtual(
  "yahoo" // can be any name for your virtual, used as key to populate
  {
    ref: "Articles",
    localField: "article", // name of field in author's schema
    foreignField: "title",    
  }
)

const Authors = mongoose.model('Authors', authorsSchema);
const Articles = mongoose.model('Articles', articlesSchema);

// using populate
Authors.find({}).populate("yahoo") // name of virtual

Enter fullscreen mode Exit fullscreen mode

There maybe some mistake in above example but hope it helps you understand the basics atleast.

Maybe once I get time to study, I will write about it as well. :)

Collapse
Β 
khanhle81839451 profile image
Khanh Le β€’

Thanks, that's helpful. But the "yahoo" could be anything, when we call .populate("field name of Authors"). There are something still not clear. However, I get over it by modify data type of _id field.

Thread Thread
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Good...things are not 100% clear to me as well...but I am sure after trying and testing we can understand it better :)

Thread Thread
Β 
njugush profile image
Njugush_Dev β€’

Hello paras wanted to know how you can find or filter items based on the populated items

Thread Thread
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Hi Neural. I don't think, we can find or filter items based on populated items. It may also slow down the query as well.
I would say, go for aggregation, because in aggregation we have better control over how we structure and filter data in different steps. Populate is good for simple to intermediate scenarios but aggregation is more helpful when you need to handle a little complex to advance scenarios

Collapse
Β 
hemantparmar profile image
hemant-parmar β€’

Hi Paras,

This was a nice read. I am going to implement this for my MEAN project. A Couple of questions.

I have a Log collection, which has 4 ObjectId type fields. i.e. client, service, executive, manager - of course apart from its own fields. And when on frontend, the Log is displayed, I am planning to populate all these 4 (i.e. Client Name, Category, Sub Category, Rating), (Service Name, Service Freq), ExecName and ManagerName.
The Log display on frontend has Search and filter options on various fields. So when a user searches or applies filters the backend Mongoose query will run again.

What would be the performance impact if the number of entries in Log collection is in the range to 5000 - 50,000?

For the above type of case would there be any other option for fetching the related data OR this is the best option.

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Though populate is not bad. It is optimised. But there is a another way. If you know about aggregation framework in mongodb then there is a $lookup option that you can add in pipeline. I am still learning about aggregation framework. I have read that $lookup is faster than populate. Try to find more about it

Just know one thing. That populate makes a second call to database. So in your case 4 populates = 4 calls.

Or, you can do a live test :p...run query with populate and check its performance then run query with $lookup pipeline and compare its performance. (mongodb has ways to check query performance)

I hope it helps you. All the best for your project :)

Collapse
Β 
hemantparmar profile image
hemant-parmar β€’

Thanks Paras for your quick response. It surely helps.

Thread Thread
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

You are welcome sir !!

Collapse
Β 
nrmad profile image
nrmad β€’

$lookup cannot be sharded and so it limits your scaling, super annoying constraint because I loved this stage until I spotted that.

Thread Thread
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Okayy. thank you !! I didn't know that :)
I still have to learn more about sharding. Never tried it.

Collapse
Β 
abdelhaqnouhi profile image
Abdelhaq Nouhi β€’

Thank you for great article.

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Welcome ❀️

Collapse
Β 
ishubham_g profile image
Shubham Gupta β€’

does the populate use find() query behind the scenes and if it does, will it also activate all the pre query middlewares of the model whose documents are used to populate?
Suppose .populate('comments')
will it also run the pre query middlewares of the ref of comments?

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Yes we can say it makes a call to find method behind the scenes. But I don't know about pre query middlewares. You have to try it once to see the outcome. Maybe it will pre query middlewares. Never really tried :)

Collapse
Β 
ishubham_g profile image
Shubham Gupta β€’

I have another question, that we also have the option to select certain fields while using populate like
.populate({path: 'comments', select: 'content name'}). Do you have some idea that it only summons that selected field or summons the whole documents and then selects the field?

Thread Thread
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Honestly I don't have idea about this one. But I can say that returning whole docs is easier because it doesn't have to convert it to partial one and return BSON data directly. So selecting specific fields adds an overhead. Don't let it discourage you from using select in populate or find.

Collapse
Β 
zinox9 profile image
Arjun Porwal β€’

Awesome . I knew this In django , Finally Got one for Node 🀘

Collapse
Β 
djnitehawk profile image
DΔ΅ ΞΞΉΞ“ΞžΞ—Ξ›ΟˆΞš β€’

does populate in mongoose issue a separate DB call for fetching the referenced documents or does it translate to a $lookup and issue a single query?

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’ β€’ Edited

No, it doesn't translate to a $lookup and Yes, it makes another query to db to get the required data.
Good question !

Collapse
Β 
djnitehawk profile image
DΔ΅ ΞΞΉΞ“ΞžΞ—Ξ›ΟˆΞš β€’

I see. yeah clientside joins are a difficult problem to solve. I've been trying to do that with my c# mongodb library but still haven't found a proper/ user friendly way. was expecting to steal it from mongoose if they've managed it 😜

Thread Thread
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

hahaha...i think you have to use $lookup and $aggregation :p

Collapse
Β 
jarvis3000 profile image
Jarvis-3000 β€’

Great bro
Very much helpful

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Thank you !!! :)

Collapse
Β 
mouna_chaib_8b2cb5111511c profile image
mouna β€’

i don't know why populate is not working for me i get a empty array

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

don't forget to add ids in that array

Collapse
Β 
mouna_chaib_8b2cb5111511c profile image
mouna β€’

yes that's why i was getting an empty array, thank you

Thread Thread
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

:) good luck !

Collapse
Β 
thegodtune profile image
Lt. Aujio Yaanji πŸ‡³πŸ‡¬ β€’

This is so much simple and concise. Thanks, Paras.

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Thank you !!...Glad you found it useful. :)

Collapse
Β 
monfernape profile image
Usman Khalil β€’

Absolute delight to read.

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

thanks !!

Collapse
Β 
varunofficial profile image
Varun β€’

good one,nice

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

thanks :)

Collapse
Β 
andrewbaisden profile image
Andrew Baisden β€’

Cool tip didn’t know this one.

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Glad you found it useful :)

Collapse
Β 
louarhou profile image
lhoussaine ouarhou β€’

Glad you found t, It's very helpfull

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Thank you !! :)

Collapse
Β 
temybroder profile image
Temitope Agboola β€’

I wonder why the populate method totally refused to work in my Express.js project. Tried everything as stated in the Mongoose Populate() documentation, yet nothing works.

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

really ?!.. what error are you getting ?

Collapse
Β 
shiva0072 profile image
Shivam Verma β€’

Thankyou. It helped.

Collapse
Β 
paras594 profile image
Paras πŸ§™β€β™‚οΈ β€’

Welcome !! :)