Mongoose: Getting defaults while querying using lean option

Created on 31 Aug 2017  路  12Comments  路  Source: Automattic/mongoose

I've added a new property to existing schema with default.
It is important for me to get it on every query.

The problem is while querying old records.
I don't want to miss the "lean" magic but I see that using lean remove virtual fields.
Currently I'm using monkey patching for populating defaults. iterating documents and schema default keys and manually add them to JSON.
Is there a point creating PR with optional query builder something as .find.lean.populateDefaults() or am I breaking the design or creating some other problem?

P.S
migrations are not an option for me.

Thanks

docs plugin

Most helpful comment

Hey guys, I've written a package to populate the default values when using lean(): mongoose-lean-defaults
It's the same idea of mongoose-lean-virtuals.
Please try it out and feel free to open an issue or a PR if something is not working

All 12 comments

Good point

Excellent point - we also encountered this problem

We are also affected. Please address.

hm this might be difficult, but i'll loop @vkarpov15 in. The whole point of lean queries is to avoid the overhead of a mongoose doc, but it might be possible with a populateDefaults function to loop over default values and populate them in a lean doc

Great feature request.

Definitely looking forward to the benefit of lean, with defaults. I found a significant slowdown and lean saved me, except I lose all the defaults.

@sonar004 can you share your monkey patch please?

@stephengardner sure:

disclaimer: I'm not sure if this relays on some internal implementation, I think not. Please share if you needed adjustments.
disclaimer2: It is correct to the version of mongoose at the time I've opened the PR.

replace: require('mongoose') with require the next file:

'use strict';

const mongoose = require('mongoose');

module.exports = ((mongoose) => {

  /**
   * Add default values of schema when using lean
   *
   * @param {Function} [model, docs]
   * @return {Query} docs
   * @api private
   */
  function populateDefaults(model, docs) {
    var schema = model.base.modelSchemas[model.modelName].obj;
    var defaultKeys = Object.keys(schema).filter(function(key) {
      return (schema[key] instanceof Object) && schema[key].hasOwnProperty('default');
    });
    return docs.map(function(doc) {
      defaultKeys.forEach(function(key) {
        if (!doc.hasOwnProperty(key)) {
          doc[key] = schema[key]['default'];
        }
      });
      return doc;
    });
  }

  /**
   * Thunk around find()
   *
   * @param {Function} [callback]
   * @return {Query} this
   * @api private
   */
  mongoose.Query.prototype._find = function(callback) {
    if (this._castError) {
      callback(this._castError);
      return this;
    }

    this._applyPaths();
    this._fields = this._castFields(this._fields);

    var fields = this._fieldsForExec();
    var options = this._mongooseOptions;
    var _this = this;

    var cb = function(err, docs) {
      if (err) {
        return callback(err);
      }

      if (docs.length === 0) {
        return callback(null, docs);
      }

      if (!options.populate) {
        return !!options.lean === true
          ? callback(null, populateDefaults(_this.model, docs))
          : completeMany(_this.model, docs, fields, null, callback);
      }

      var pop = helpers.preparePopulationOptionsMQ(_this, options);
      pop.__noPromise = true;
      _this.model.populate(docs, pop, function(err, docs) {
        if (err) return callback(err);
        return !!options.lean === true
          ? callback(null, docs)
          : completeMany(_this.model, docs, fields, pop, callback);
      });
    };

    return mongoose.Query.base.find.call(this, {}, cb);
  };

  return mongoose;
})(mongoose);

Hey guys, I've written a package to populate the default values when using lean(): mongoose-lean-defaults
It's the same idea of mongoose-lean-virtuals.
Please try it out and feel free to open an issue or a PR if something is not working

@DouglasGabr thanks for the plugin :+1: it looks great, I just added a quick PR, and I'll add a note about this to the docs tomorrow

@vkarpov15 I've just released a new version with your changes

Was this page helpful?
0 / 5 - 0 ratings