Mongoose: Setting nested properties not working correctly

Created on 25 Apr 2019  路  5Comments  路  Source: Automattic/mongoose

This is actually extremely similar to #7707. I'm opening a new issue as requested by @vkarpov15 .

Since 5.4.19 our build has been failing because it looks like nested properties are not being set correctly (or even set to undefined).

In our own case this is happening with Number fields that are set to undefined and then when mongoose tries to cast them to numbers, they become NaN (Number(undefined) -> NaN) https://travis-ci.org/HabitRPG/habitica/jobs/524634104

I can followup with a different repro script if needed but this code posted in #7707 by @Msordet works in reproducing the issue

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

// Fix all deprecation warnings: https://mongoosejs.com/docs/deprecations.html
mongoose.set("useNewUrlParser", true);
mongoose.set("useFindAndModify", false);
mongoose.set("useCreateIndex", true);

const geojsonSchema = new Schema(
  {
    type: { type: String, default: "Feature" },
    geometry: {
      type: {
        type: String,
        enum: [
          "Point",
          "MultiPoint",
          "LineString",
          "MultiLineString",
          "Polygon",
          "MultiPolygon",
          "GeometryCollection"
        ],
        required: true
      },
      coordinates: { type: [] }
    },
    properties: { type: Object }
  },
  {
    _id: false,
    timestamps: {
      createdAt: true
    }
  }
).index({ geometry: "2dsphere" });

const userSchema = new Schema({
  position: geojsonSchema
});

const GeoJson = mongoose.model("GeoJson", geojsonSchema);
const User = mongoose.model("User", userSchema);

mongoose.connect("mongodb://localhost:27017/test-nested").then(async () => {
  const position = new GeoJson({
    geometry: {
      type: "Point",
      coordinates: [1.11111, 2.22222]
    },
    properties: {
      a: "b"
    }
  });

  const newUser = new User({
    position
  });
  try {
    await newUser.save();
  } catch (e) {
    console.log("Fail at user creation");
    console.error(e);
  }

  const editUser = await User.findById(newUser._id);

  editUser.position = position;

  try {
    await position.validate();
    await editUser.validate();
  } catch (e) {
    console.log("Fail at user validation");
    console.error(e);
  }
});
confirmed-bug

Most helpful comment

Sorry for the trouble @paglias , we did some work to make sure single nested setters could modify other properties in single nested subdocs and it has caused a few issues. I believe I fixed this issue, will double check @Fonger 's repro script later.

All 5 comments

I think this is a priority issue. After investigation, I find out that this is caused by the fix for #7660 and the commit 6c66ba875cf38ff865198505c1b3bf4db18e4fd7
This line delete your geometry.type
https://github.com/Automattic/mongoose/blob/de6652086e41b729bcb3254edc758e397a0a8e65/lib/types/subdocument.js#L41

I'm not fully understand the code here so I'm afraid to change it. @vkarpov15 what do you think?

A simpler repro script, basically, this bug can be reproduced if you have an inline schema under a nested mongoose.Schema.

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

mongoose.set("useNewUrlParser", true);
mongoose.set("useFindAndModify", false);
mongoose.set("useCreateIndex", true);

const nestedSchema = new Schema({
  name: { type: String, required: true },
  nestedInline: {
    deep: { type: String, required: true }
  }
})

const userSchema = new Schema({
  nestedWithSchema: nestedSchema // if you inline all schema here, everything works fine.
});

const User = mongoose.model("User", userSchema);

mongoose.connect("mongodb://localhost:27017/test-nested").then(async () => {
  const newUser = new User({
    nestedWithSchema: {
      name: 'Fonger',
      nestedInline: {
        deep: 'very deep!'
      }
    }
  });

  await newUser.save();

  const editUser = await User.findById(newUser._id);
  editUser.nestedWithSchema = { name: 'Fonger2', nestedInline: { deep: 'even deeper' } }
  console.log(editUser);
  /*
    { _id: 4cc22cfbc5564134328401f4,
      nestedWithSchema: { name: 'Fonger2' },  // nestedInline is missing
      __v: 0 }
  */

  try {
    await editUser.validate();
  } catch (e) {
    console.log("Fail at user validation");
    console.error(e);
  }
});

Sorry for the trouble @paglias , we did some work to make sure single nested setters could modify other properties in single nested subdocs and it has caused a few issues. I believe I fixed this issue, will double check @Fonger 's repro script later.

@vkarpov15 thanks! I can confirm that this commit actually fixes the issue

Confirmed, fixed by 5aa79c2

Thanks for reporting this issue @paglias :+1:

Was this page helpful?
0 / 5 - 0 ratings