Home > database >  Can only define custom mongoose methods in options
Can only define custom mongoose methods in options

Time:09-28

According to the mongoose docs, there are 3 ways to add custom methods to your documents:

  1. Through schema options
  2. Directly assigning a "methods" object to the schema
  3. Using the Schema.method() helper

However, after many tries, I have only managed to get methods working using option 1. I am curious as to why options 2 & 3 are not working for me. here is my code:

app.js

socket.on("message", async function (clusterData, callback) {
  console.log("socket event fired");
  const parentCluster = await Message.findById(clusterData.clusterId);
  coonsole.log(parentCluster); // exists as expected

  parentCluster.optionsMethod(); // log : "options method called" ✔
  parentCluster.objectMethod(); // error : parentCluster.objectMethod is not a function ❌
  parentCluster.helperMethod(); // error : parentCluster.helperMethod is not a function ❌
});

Message.js

import mongoose from "mongoose";

const messageSchema = new mongoose.Schema({
  mentions: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
  text: { type: String, trim: true },
  file: { type: String },
  dateString: { type: String, required: true },
  timestamp: { type: Number, required: true },
});

const messageClusterSchema = new mongoose.Schema(
  {
    sender: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
    channel: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Channel",
      required: true,
    },
    group: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Group",
      required: true,
    },
    content: [messageSchema],
    clusterTimestamp: {
      type: Number,
      required: true,
    },
  },
  {
    toObject: { virtuals: true },
    toJSON: { virtuals: true },
    methods: {
      optionsMethod() {
        console.log("options method called");
      },
    },
  }
);
messageClusterSchema.virtual("lastMessage").get(function () {
  return this.content[this.content.length - 1];
});

messageClusterSchema.pre("validate", function () {
  console.log("pre validate ran");
  this.clusterTimestamp = this.content[this.content.length - 1].timestamp;
});


// assign directly to object
messageSchema.methods.objectMethod = function () {
  console.log("object method called");
};

// assign with helper
messageSchema.method("helperMethod", function () {
  console.log("helper method called");
});

console.log(messageSchema.methods); // {objectMethod: [Function (anonymous)], helperMethod: [Function (anonymous)]}
console.log(messageSchema.methodOptions); // { helperMethod: undefined }

const Message = mongoose.model("Message", messageClusterSchema);

export default Message;

CodePudding user response:

The issue is that, objectMethod and helperMethod is in messageSchema and In Message.js file, you are creating model of messageClusterSchema which you are importing and using in socket function. Both methods can only be called with a model-instance of messageSchema. And that's why optionsMethod is calling, but the other two are not. Basically you need to create model of messageSchema and export it to use it in other files.

In short, the error is:

const Message = mongoose.model("Message", messageClusterSchema);

The model is generated using messageClusterSchema, but the methods are assigned to messageSchema:

messageSchema.methods.objectMethod = function () {
  console.log("object method called");
};

// assign with helper
messageSchema.method("helperMethod", function () {
  console.log("helper method called");
});

They should be assigned to messageClusterSchema.

  • Related