Mongoose: Allow specifying default projection for populated fields

Created on 23 Jan 2018  路  6Comments  路  Source: Automattic/mongoose

Do you want to request a feature or report a bug?
Feature

What is the current behavior?
Currently, if you populate on a field with no projection specified, it puts the entire document in by default.

I've realized that most of the time I really only want a pretty limited subset of those fields when I'm populating a field for a document (for example, the first and last names of a user vs. all of their related profile data). It also tends to get messy when there are multiple fields to populate. I think a simple way to introduce this would be another property in schema definitions that can be used when using ref. For example, something like this would work:

const messageSchema = new Schema({
  text: String,
  date: Date,
  user: { ref: 'User', populate: 'firstName lastName' }
})

// ...

const message = await Message.findById(id).populate('user')
console.log(message.user) // { firstName: 'Kyle', lastName: 'Herock' }

Please mention your node.js, mongoose and MongoDB version.
Node 8, Mongoose 5.0, MongoDB 3.6

new feature

Most helpful comment

@AbdullahAli no updates yet, please follow this issue for updates.

All 6 comments

sure, i can label this a feature request, but how would you recommend overriding the defaults in the case where you do want the entire object? Would the user need to specify each and every field in the schema then?

Any update on this please? This would be very useful!

@AbdullahAli no updates yet, please follow this issue for updates.

Populate is a 2 edge sword. It provides convenience, yet at the expense of convenience, you may accidentally leak passwords and other sensitive information when you populate a user field without specifying the fields.

IMO, by default, populate should require developers to choose the fields to populate, or { path: 'user', select : 1 } to populate everything.

I wonder how many passwords are being leaked unnecessarily because developers don't check the returned objects.

Possible workarounds
.populate('field', 1) //1 to indicate all
or
.populate( path: 'field', select: 1) to indicate all

Thanks for the hardwork.

@daveteu thanks for your feedback. However, that sounds like a symptom of bad schema design, like the anti-pattern of storing password hashes on user documents. If you find yourself wanting to exclude a field all the time, then you should consider storing it in a separate model. Store what you query for.

We'll bump this issue up for v5.11 :+1:

In v5.11 you'll be able to do this:

    const parentSchema = Schema({
      child: {
        type: 'ObjectId',
        ref: 'Child',
        populate: { select: 'name' }
      }
    });
Was this page helpful?
0 / 5 - 0 ratings