These are chat archives for Automattic/mongoose

30th
May 2018
Alex Korsun
@koralex_gitlab
May 30 2018 17:17
Hi there! I'm facing an issue with discriminator. I'm using feathersjs with mongoose. The actual issue is that I can't update single document. Feathers passes all data to mongoose, request passes successfully but data doesn't change. Mongoose version - 4.8.6.
Kev
@lineus
May 30 2018 17:18
@koralex_gitlab it's hard to say without seeing a code sample. Can you share your schema, model/discriminator creation, and the relevant update operation?
Alex Korsun
@koralex_gitlab
May 30 2018 17:24

@lineus https://github.com/feathersjs-ecosystem/feathers-mongoose#discriminators-inheritance

const service = require('feathers-mongoose');
const WorkflowModel = require('./workflow-model');
const TargetedContactsSchema = require('./schemas/targetedContacts');
const hooks = require('./hooks');

module.exports = function setupWorkflowService() {
  const app = this;

  const connection = app.get('mongoose');
  const schemaOptions = { discriminatorKey: '__type' };

  const workflowModel = WorkflowModel(connection, schemaOptions);
  const targetedContacts = workflowModel.discriminator('targeted-contacts', TargetedContactsSchema(schemaOptions));

  const options = {
    Model: workflowModel,
    paginate: {
      default: 10,
      max: 100,
    },
    discriminators: [targetedContacts],
  };

  const workflowService = service(options);

  // Initialize our service with any options it requires
  app.use('/workflows', workflowService);

  // Bind our hooks
  app.service('/workflows')
    .before(hooks.before)
    .after(hooks.after);
};
/**
 * Workflow settings
 */

const mongoose = require('mongoose');

const Schema = mongoose.Schema;

module.exports = function workflowModel(connection, options) {
  const workflowSchema = new Schema({
    /**
     * Owner
     * Defines who can access and modify the user.
     */
    owner: {
      type: String,
      index: true,
      required: true,
      reference: 'user',
      cascadeDelete: true,
    },

    flow: {
      type: String,
    },

    /**
     * Creation date
     * When the user was created.
     */
    created_at: { type: Date, default: Date.now },

    /**
     * Update date
     * When the user was last updated.
     */
    updated_at: { type: Date, default: Date.now },
  }, options);

  return connection.model('workflows', workflowSchema);
};
const mongoose = require('mongoose');

const Schema = mongoose.Schema;

module.exports = function setTargetedContactsSchema(options) {
  const conditionSchema = new Schema({
    _id: false,
    id: false,
    field: {
      type: String,
      required: true,
    },
    operator: {
      type: String,
      enum: ['regex', 'contains', 'is', 'is not', 'greater than', 'lower than', 'is empty', 'is not empty'],
      required: true,
    },
    value: {
      type: String,
      required: true,
    },
  });

  const ruleSchema = new Schema({
    _id: false,
    id: false,
    combinationOperator: {
      type: String,
      enum: ['and', 'or'],
      default: 'and',
      required: true,
    },
    conditions: [conditionSchema],
  });


  const reportSchema = new Schema({
    _id: false,
    id: false,
    type: {
      type: String,
      enum: ['email', 'account'],
      required: true,
    },
    parameters: {
      type: mongoose.Schema.Types.Mixed,
      required: true,
    },
  });

  const targetedContactsSchema = new Schema({
    /**
     * Schedule
     */
    schedule: {
      type: String,
      enum: ['1 minute', '10 minutes', '1 hour', '1 day', '10 seconds'],
      required: true,
    },

    report: reportSchema,

    rule: ruleSchema,
  }, options);

  return targetedContactsSchema;
};

Actually, the update call is initiated by feathers service, so I do nothing for this, just make request from the client-side. I've checked the data which passes through feathers-mongoose adapter and what mongoose model update method receives. And it seems that data is correct as expected and model.update is called.

Upgrade to the latest version of mongoose didn't help actually.
Kev
@lineus
May 30 2018 17:32
@koralex_gitlab what does the update call that feathers sends look like?
Alex Korsun
@koralex_gitlab
May 30 2018 17:33
@lineus
{
    key: 'patch',
    value: function patch(id, data, params) {
      var _this = this;

      var query = Object.assign({}, (0, _feathersQueryFilters2.default)(params.query || {}).query);
      var mapIds = function mapIds(page) {
        return page.data.map(function (current) {
          return current[_this.id];
        });
      };

      // By default we will just query for the one id. For multi patch
      // we create a list of the ids of all items that will be changed
      // to re-query them after the update
      var ids = id === null ? this._find(params).then(mapIds) : Promise.resolve([id]);

      // Handle case where data might be a mongoose model
      if (typeof data.toObject === 'function') {
        data = data.toObject();
      }

      // ensure we are working on a copy
      data = Object.assign({}, data);

      // If we are updating multiple records
      var options = Object.assign({
        multi: id === null,
        runValidators: true,
        context: 'query'
      }, params.mongoose);

      if (id !== null) {
        query[this.id] = id;
      }

      if (this.id === '_id') {
        // We can not update default mongo ids
        delete data[this.id];
      } else if (id !== null) {
        // If not using the default Mongo _id field set the id to its
        // previous value. This prevents orphaned documents.
        data[this.id] = id;
      }

      // NOTE (EK): We need this shitty hack because update doesn't
      // return a promise properly when runValidators is true. WTF!
      try {
        return ids.then(function (idList) {
          // Create a new query that re-queries all ids that
          // were originally changed
          var findParams = Object.assign({}, params, {
            query: _defineProperty({}, _this.id, { $in: idList })
          });

          if (params.query && params.query.$populate) {
            findParams.query.$populate = params.query.$populate;
          }

          // If params.query.$populate was provided, remove it
          // from the query sent to mongoose.
          return _this.Model.update((0, _lodash2.default)(query, '$populate'), data, options).lean(_this.lean).exec().then(function () {
            return _this._getOrFind(id, findParams);
          });
        }).then((0, _feathersCommons.select)(params, this.id)).catch(_errorHandler2.default);
      } catch (e) {
        return (0, _errorHandler2.default)(e);
      }
    }
  }
Kev
@lineus
May 30 2018 17:39
heh, it's a little known fact that snarky comments in source code generate issues in the appropriate queue on github.
@koralex_gitlab can you turn on mongoose debugging ( mongoose.set('debug', true) and see what update call is actually made?
Alex Korsun
@koralex_gitlab
May 30 2018 17:49
@lineus good point
{ owner: 'auth0|5abb590c0be6766e04178cd4',
  report: { type: 'email', parameters: { email: 'test@test.com' } },
  rule: 
   { combinationOperator: 'and',
     conditions: [ { field: 'person_email', value: '1222', operator: 'contains' } ] },
  schedule: '1 day',
  __type: 'targeted-contacts',
  updated_at: 2018-05-30T17:44:24.060Z }
Mongoose: workflows.update({ _id: ObjectId("5b0edf13acba950237283fe7") }, { '$set': { updated_at: new Date("Wed, 30 May 2018 17:44:24 GMT"), __type: 'targeted-contacts', owner: 'auth0|5abb590c0be6766e04178cd4' } }, { multi: false, runValidators: true, context: 'query' })
Mongoose: workflows.findOne({ _id: ObjectId("5b0edf13acba950237283fe7") }, { fields: {} })
Kev
@lineus
May 30 2018 18:15
@koralex_gitlab is it one field in particular that isn't updated? or are no fields updated?
Alex Korsun
@koralex_gitlab
May 30 2018 18:16
@lineus the first piece is the doc which receive mongoose update method. so the mongoose actually does update with data of base model.
Alex Korsun
@koralex_gitlab
May 30 2018 18:23
I can't understand why mongoose doesn't deal with discriminator type, when I provide it with the data. I imagine that when I use base model and data contains discriminator it should trigger discriminator model instead of base model.
Kev
@lineus
May 30 2018 18:26
which version of feathers-mongoose @koralex_gitlab ?
Alex Korsun
@koralex_gitlab
May 30 2018 18:27
@lineus 3.6.2
Kev
@lineus
May 30 2018 18:35
@koralex_gitlab you mentioned trying with the latest version of mongoose, did you also try a later version of feathers-mongoose? They're up to version 6.1.1 now.
I'm not seeing anything obviously wrong with it, the only other thing that I could do is clone your repo and play with it if you like
Alex Korsun
@koralex_gitlab
May 30 2018 18:41
@lineus yes, I tried to check it with latest version of feathers-mongoose. but it didn't help. the issue of this as I see, is that feathers-mongoose doesn't deal with discriminator type and doesn't swap to correct model. So it uses just base model and that's why I can update just fields from base model
Kev
@lineus
May 30 2018 18:49
when you pass in the _id for your update query, are you passing in the discriminatorKey also?

from the feathers-mongoose docs:
Now in your query, you can specify a value for your discriminatorKey

{
  _type: 'text'
}

and Feathers will automatically swap in the correct model and execute the query it instead of its parent model.

TheRedstoneTaco
@TheRedstoneTaco
May 30 2018 19:38
@TheRedstoneTaco
where can I learn to authorize so only users who have successfully paid will have the backend add the ebook id into their ebooks array (so they can now read it)?
I'm using paypal for now, but if credit cards are easier for beginners, I can do that
Alex Korsun
@koralex_gitlab
May 30 2018 20:26
@lineus actually _id set by feathers, but yes, I tried to add discriminator key to query and it does not help
Kev
@lineus
May 30 2018 21:30
yeah, I just recreated the example from the feathers-mongoose docs and no matter what I do it just uses the base Model.
@koralex_gitlab ^
Kev
@lineus
May 30 2018 21:40
sorry I wasn't able to actually help :shit:
Alex Korsun
@koralex_gitlab
May 30 2018 21:41
@lineus ahahha, NP
anyway, you tried at least ;) thanks
Kev
@lineus
May 30 2018 21:42
sometimes sleeping on it helps, maybe I'll have an epiphany tonight
it was fun trying :)