Using dynamic references with Node.js and mongoose ‘refPath’

Jose Arrillaga
2 min readApr 17, 2021

--

Photo by Ben White on Unsplash

While doing a bit of refactoring lately, I decided to re-design an old schema using nested “dynamic refs” instead of normal refs with server-side logic checks. After all, it seemed like the best way to avoid the crazy conditional checks I was running every time I fetched data.

My original schema was this:

Fig. 1 — Original schema with normal ref.

My log schema was this:

Fig. 2 — Schema for log.

Where I would leave task as undefined if I was tracking a workOrder or viceversa.

That, of course, gets messy when populating and displaying data so naturally I wanted to figure out a way to make use of dynamic refs.

The wrong way to do it.

Upon reading the mongoose docs, I assumed I could get away with doing the following:

Fig. 3 — refPath with wishful thinking.

While this looks elegant, when we call model.find().populate('session.firstAcitivity.logId'), mongoose will spit out an error about not being able to find the model type to use for the populate action.

This is because in the new logSchema we defined above, we are telling mongoose that the refPath for logId will be resolved via logType. However, when we nest that schema somewhere else, that refPath is no longer valid.

Mongoose needs an absolute and unambiguous string to resolve refPath!

[TL;DR] The right way to do it.

In fact, what we have to do is write our schema the following way:

Fig. 4 — refPath done right!

While this looks more verbose, our populate logic is very straightforward now; a simple query

model.
find().
populate('session.firstActivity.logId').
exec();

will unambiguously fetch the data we want.

And it works with arrays, too! populate('session.activities.logId') instead, will give us the populated documents just as expected.

A closing note about using refPath. While it is a very powerful tool, it requires defining additional models (those defined in enum: ['taskLog', 'workOrderLog']). The trade-off, of course, is more readable code, if used properly.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Jose Arrillaga
Jose Arrillaga

Written by Jose Arrillaga

Founder @ UAME. I like to write about solutions to problems that vexed me the previous week.

Responses (3)

Write a response