Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue when assigning values to nested fields #9459

Closed
ruizmurcia opened this issue Oct 2, 2020 · 3 comments
Closed

Issue when assigning values to nested fields #9459

ruizmurcia opened this issue Oct 2, 2020 · 3 comments
Milestone

Comments

@ruizmurcia
Copy link

ruizmurcia commented Oct 2, 2020

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

What is the current behavior?
From v5.9.10 and later we have experienced a change in the behaviour when assigning a value to a nested property of a model. Let's take this script as an example:

'use strict';

const mongoose = require('mongoose');

const { Schema } = mongoose;

run().catch(err => console.log(err));

async function run() {
  await mongoose.connect('mongodb://localhost:27017/test', {
    useNewUrlParser: true,
    useUnifiedTopology: true
  });

  await mongoose.connection.dropDatabase();

  const preferencesSchema = mongoose.Schema({
    notifications:  {
      email: Boolean,
      push: Boolean
    },
    keepSession: Boolean
  },{ _id: false });

  const User = mongoose.model('User', Schema({
    email: String,
    username: String,
    preferences: preferencesSchema
  }));

  const userFixture = {
    email: 'foo@bar.com',
    username: 'foobars',
    preferences: {
      keepSession: true,
      notifications: {
        email: false,
        push: false
      }
    }
  };

  const userWithEmailNotifications = Object.assign({}, userFixture, {
    'preferences.notifications': { email: true}
  })

  const testUser = new User(userWithEmailNotifications)

  console.log('User', testUser);
}

The result is that no change is made to the nested property:

User {
  _id: 5f76e44107612fccf0b2f733,
  email: 'foo@bar.com',
  username: 'foobars',
  preferences: { keepSession: true, notifications: { email: false, push: false } }
}

What is the expected behavior?
In v5.9.9 and previous versions the same code results in changing the property:

User {
  _id: 5f76e4b01dc7eacd204ab418,
  email: 'foo@bar.com',
  username: 'foobars',
  preferences: { keepSession: true, notifications: { email: true, push: false } }
}

After looking for differences between v5.9.9 and v5.9.10 we have found that the issue is cause by the change in:
8fea1d9

This feels like a bug, though it may be intended behavior.

Could you please give us some clarification on the issue?

Thank you so much!

@vkarpov15 vkarpov15 added this to the 5.10.8 milestone Oct 4, 2020
vkarpov15 added a commit that referenced this issue Oct 4, 2020
@vkarpov15
Copy link
Collaborator

Thank you for looking into this. This issue is due to Mongoose not handling nested paths within nested subdocs when setting a dotted path correctly, in either the v5.9.9 or the v5.10.10 behavior. The correct output is:

User {
  _id: 5f76e4b01dc7eacd204ab418,
  email: 'foo@bar.com',
  username: 'foobars',
  preferences: { keepSession: true, notifications: { email: true } }
}

Because you're explicitly setting preferences.notifications, as opposed to just preferences.notifications.email. The v5.9.9 behavior was due to the fact that Mongoose wasn't able to find the correct schema type for preferences.notification when setting.

In v5.10.8 we'll change it so that the output is notifications: { email: true }. Does that work for you or do you need a workaround?

@ruizmurcia
Copy link
Author

Thank you very much quick reply.

In our test suit we have a base object that we modified in each test depending on the conditions. What we expect is to merge the existing properties of the object userFixture, with the new properties that we have specified using the Object.assign method. We don't want to just overwrite them.

The behaviour in version v5.9.9 and previous was perfect for us, and we expect to get the following:

User {
  _id: 5f76e4b01dc7eacd204ab418,
  email: 'foo@bar.com',
  username: 'foobars',
  preferences: { keepSession: true, notifications: { email: true, push: false } }
}

Is there any workaround that we can implement to have this same result even in v5.10.8?

@vkarpov15
Copy link
Collaborator

Would it be possible for you to do:

  const userWithEmailNotifications = Object.assign({}, userFixture, {
    'preferences.notifications.email': true
  })

instead?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants