laggingreflex
laggingreflex

Reputation: 34667

Populate all fields in mongoose?

Is there a way to populate all fields when running a mongoose query, in case you don't know in advance which fields are the referenced documents? Something like this:

schema = new Schema({ ref: {type:ObjectId, ref:'ref'}});
db = Model('data', schema);

db.find({}).populate('*').
// or
db.find({}).populate({path:'*'}).

//=> {ref: {_id:...,}} // "ref" is populated automatically

Upvotes: 6

Views: 8917

Answers (3)

rbertolig
rbertolig

Reputation: 1

In my case, for each Model I also have a Class, and inside that Class I include some methods which returns the relevant information required for each case. This allow me to create custom lists of 'filtered' fields per class, used on query options for: what to return on GET routes, what is allowed to modify on PUT routes, and which fields to populate... etc.

When need to add or remove any 'allowed' field just do it on the class method, not all over the rest of the code.

example:

// all imports done

class Users {
  // Query parameters
  sortBy() { return 'name'; } 
  getAllFieldsFilter() { return 'name email membertype created_at updated_at'; }
  getAllPopulateIndexed() { return { path: 'membertype', select: 'name canpost' };}
  
  // other methods...
  constructor() {}
}
module.exports = {
  Users,
};

Later it can be used on the queries, for example:

User.find(queryOptions, Users.getAllFieldsFilter())
  .sort(Users.sortBy())
  .populate(Users.getAllPopulateIndexed());

Upvotes: 0

Mojtaba Razaghi
Mojtaba Razaghi

Reputation: 349

I think it's better to export a variable somewhere that contains the list of all populated fields like :

export const POPULATED_FIELDS = ['filed1','field2']

then when you want to populate the fields just wrtie

Model.findById('some_id').populate(POPULATED_FIELDS)

Upvotes: 2

laggingreflex
laggingreflex

Reputation: 34667

I wrote a small plugin. It goes through the schema and looks for fields with a ref property and adds them as a path which is fed to .populate() in a pre-find hook. Tested with Mongoose v4

function autoPopulateAllFields(schema) {
    var paths = '';
    schema.eachPath(function process(pathname, schemaType) {
        if (pathname=='_id') return;
        if (schemaType.options.ref)
            paths += ' ' + pathname;
    });

    schema.pre('find', handler);
    schema.pre('findOne', handler);

    function handler(next) {
        this.populate(paths);
        next();
    }
};
module.exports = autoPopulateAllFields;
var articleSchema = new Schema({
    text: {type: 'String'},
    author: {type: 'ObjectId', ref: 'user'}
});
articleSchema.plugin(autoPopulateAllFields);
var Article = mongoose.model('article', articleSchema);
Article.find({}) => [ {text:..., author: { _id:..., name:... /*auto-populated*/} } ]

Upvotes: 6

Related Questions