0

I am working through a tutorial, building a small library DB in Express and Mongoose. In the tutorial each book can have one of several statuses, and only one of those values. It's an Enum. I am handling this by putting an array of values in the BookInstance schema:

var the_statuses = ['Available', 'Maintenance', 'Loaned', 'Reserved'];

which works fine when I have an instance -- I use a virtual method to fetch those values

BookInstanceSchema
    .virtual('statuses')
    .get(function() {
      return the_statuses;
    });

when I, as said, have an instance already.

And when creating the Schema I access my local variable as, well, a local variable:

var BookInstanceSchema = Schema({
  book: { type: Schema.ObjectId, ref: 'Book', required: true }, //reference to the associated book
  imprint: {type: String, required: true},
  status: {type: String, required: true, enum: the_statuses, default: 'Maintenance'},
  due_back: {type: Date, default: Date.now},
});

But what if I want to simply get the enum values directly from the schema but from outside the schema? That is, if I want to create, in this case, a BookInstance instance, and offer the user a choice of statuses in a select menu, I won't have access to an instance yet (unless I kludge it and simply create one to grab the enum values).

I tried making a static function

BookInstanceSchema.statics.getStatuses = function() {
    return this.the_statuses;
};

But it doesn't seem to work.

What's the best way to do what I'm trying to do? Is there such a thing as a "static virtual method" in Mongoose?

Cerulean
  • 3,591
  • 31
  • 63

1 Answers1

1

It's been a little bit since I have used MongoDB (and Mongoose, obviously), but static methods don't have access to instances. Thus, you really shouldn't be using this inside a static method. Additionally, it doesn't appear that an instance of BookInstanceSchema has a property the_statuses (just the virtual statuses). Judging from your code, it looks like you would have access to the the_statuses variable in your BookInstanceSchema definition. So, why not use it directly?

BookInstanceSchema.statics.getStatuses = function() {
    return the_statuses;
};

// Use like
BookInstanceSchema.getStatuses();

EDIT:

For more general information on this in JavaScript, check out this post, and MDN docs. In brief, it's behavior changes when in "strict" mode, and it can be manipulated by the Function class's methods .call and .apply, to name a few of the oddities.

You'd be right to assume that this would refer to the object with which a given method was called, as that is default behavior. In our case, that object would be BookInstanceSchema.statics. But, there's the case that Mongoose calls any method under statics in a different context (i'm assuming here), like BookInstanceSchema, but it certainly does not call from the context of an instance, that's the context that methods on BookInstanceSchema.methods would be called in. It needs to be noted that this is completely non-standard. Mongoose is essentially mimicking OOP concepts like Class Methods, and Instance Methods (Schema.statics and Schema.methods, respectively). In the case of Mongoose, i'm not sure which object this refers to in methods on Schema.statics, but it definitely refers to the instance object on Schema.methods.

As the "class" syntax gets older (brought forth in ES2015) more libraries will probably accommodate a more "standard" way to define Class Methods and Instance Methods (Sequelize is working on this in their next release). Additionally, OOP concepts like Class Methods and Instance Methods are achievable in JS, albeit a little differently. if you're interested, this article will shed a lot of light on how that works in Vanilla JS, along with great examples of the new class syntax contrasted with the older function-prototype syntax.

undefined
  • 2,014
  • 13
  • 16
  • Worked perfectly. Although I've programmed a long time, it's been in other languages and the "this" of Javascript sometimes throws me. In this context, one must be inside an instance to refer to 'this'? As I understand it, 'this' refers to the object/code structure from which a function is called -- but if you call a static method in Mongoose, it's being called _from_ something? I think I may be mixing and matching OOP -- which is what I'm used to -- and the Javascript world, but I'm keen to understand _why_ your solution worked. But anyway, thanks! – Cerulean Jul 03 '17 at 22:27
  • Glad it helped. Yeah, `this` is very weird in JS, even more so in the context of Mongoose. Will edit the answer with some details. – undefined Jul 03 '17 at 22:33