question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Proposal] Reconsidering validator contexts and calling behavior

See original GitHub issue

When updating a property of a sub doc, like so:

doc.sub.property = "value"
doc.save()

Its validators are called twice, once in the context of the main doc and once in the context of the sub doc. This is probably intended behavior, however I would really consider thinking about this.

I encountered this “feature” because I needed to access a property’s siblings in its validator function (f.i. to check whether a date is before another stored in the database). The current behavior makes the validator never pass, because depending on what context (this) you rely on, the following is thrown for the other context: Cannot read property x of undefined.

Now, I know I can easily work around this by normalizing what I receive, something along the lines of:

let sub = this.sub || this

But this is just a hack, I think we face a more fundamental problem because Mongoose passes varying contexts to validators (and possibly more functions that operate on properties, like required, set…).

I think we should always start from the smallest document instance, because, while providing the parent (more possibly useful data) seems tempting, using the sub doc as a standalone would create varying contexts once again. (However I’m not sure whether that should be allowed anyway, but that’s topic for another discussion :p.) We could enhance the context if we have more data to provide.

What if validators (and other functions) would receive something like below as value for this?

{
	document: {
		// properties of sub doc
		sample: "test"
		// ...
	},
	parent: {
		// properties of parent
		subdoc: {
			sample: "test"
		}
		// ...
	}
}

Note I chose for an extra layer to prevent naming conflicts with document properties, and allow for extensibility. (Monoose could hook extra properties and methods to this, that validators could use…) When used as a standalone, parent will not be present obviously. document should still be present though, to ensure we always provide the same context upon which we can rely then.

This would go behind an option (f.i. richContext) of course, to ensure backwards compatibility.

However, validators are still being called twice in some scenarios, which is redundant and inefficient. I think we should address that too. The validation should only be called on the sub doc level, in line with the reasoning above.

Let me know what you think 😃

I’m using Mongoose 4.9.7 as of writing.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
sobafuchscommented, May 7, 2017

yeah i think this is an issue too, and it certainly feels like a hack to do something like:

let sub = this.sub || this;

i think this is a repro script that captures the problem:

const mongoose = require('mongoose');
const co = require('co');
mongoose.Promise = global.Promise;
const GITHUB_ISSUE = `gh-5224`;


exec()
  .then(() => {
    console.log('successfully ran program');
    process.exit(0);
  })
  .catch(error => {
    console.error(`Error: ${ error }\n${ error.stack }`);
  });


function exec() {
  return co(function*() {
    const db = mongoose.createConnection(`mongodb://localhost:27017/${ GITHUB_ISSUE }`);
    const subSchema = new mongoose.Schema({
      name: String
    });

    // this only runs once
    subSchema.path('name').validate(function(name) {
      console.log('this', this.name); // undefined in context of parent schema
      // console.log('parent', this.parent()); // this would error
      return true;
    });

    const schema = new mongoose.Schema({
      subDoc: subSchema,
      age: Number
    });

    const Model = db.model('Model', schema);

    yield Model.remove({});
    
    const doc = new Model({ subDoc: { name: 'Test' }, age: 24 });

    yield doc.save();

    doc.subDoc.name = 'Another name';

    yield doc.save();
  });
}

I wonder if running the validators only once would be considered a breaking backwards change though so only fit for a major release? I’m of the opinion that it’s not backwards breaking, but open to discussion

0reactions
vkarpov15commented, Oct 19, 2022

This looks fixed in Mongoose 6. Running the following script:

const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const GITHUB_ISSUE = `gh-5224`;


exec()
  .then(() => {
    console.log('successfully ran program');
    process.exit(0);
  })
  .catch(error => {
    console.error(`Error: ${ error }\n${ error.stack }`);
  });


async function exec() {
    const db = mongoose.createConnection(`mongodb://localhost:27017/${ GITHUB_ISSUE }`);
    const subSchema = new mongoose.Schema({
      name: String
    });

    // this only runs once
    subSchema.path('name').validate(function(name) {
      console.log('this', this.name); // undefined in context of parent schema
      console.log('parent', this, this.parent()); // this would error
      return true;
    });

    const schema = new mongoose.Schema({
      subDoc: subSchema,
      age: Number
    });

    const Model = db.model('Model', schema);

    await Model.remove({});

    const doc = new Model({ subDoc: { name: 'Test' }, age: 24 });

    await doc.save();

    doc.subDoc.name = 'Another name';

    await doc.save();
}

shows that the value of this in the validator is in fact the subdocument. I’ll close this issue for now. Please re-open if this is still an issue.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Parking Lot Milestone · GitHub
Make update validators fail if upsert is set and required path isn't in $set or ... [Proposal] Reconsidering validator contexts and calling behavior...
Read more >
JSMF Opportunity Awards- 2022 Final Call for Applications
This call for proposals is focused on applications from researchers who are not currently using the approaches described in this call for proposals,...
Read more >
Rethinking validation in complex high-stakes assessment ...
In this article we rethink validation within the complex contexts of high-stakes assessment. We begin by considering the utility of existing models for ......
Read more >
Validation-and-psychotherapy.pdf - ResearchGate
These acceptance strategies are balanced by corresponding "change" strategies of problem solving (including behavioral analyses, analyses of alternative ...
Read more >
Reconsidering Attachment in Context of Culture: Review of ...
This paper revisits the attachment controversies, reexamining the debates regarding attachment phenomenon being universal or culture-specific, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found