Search code examples
mongoosemongoose-schema

Mongoose Remove Fields not on schema on read/find


I have a schema:

const LinkSchema = new mongoose.Schema({
    name: { type: String },
    style: { default: "icon", type: String },
});

And a document already in mongoDB with potentially many old fields.

{
   "name": "abcLink",
   "oldThing1": true,
   "oldThing2": "oeunth",
   ....
   "oldThing100": "hi",
}

I want link.findOne({ name: "abcLink" }) to return

{
   "name": "abcLink",
   "style": "icon"
}

Currently, I get

{
   "name": "abcLink",
   "oldThing": true,
   "style": "icon"
}

How can I have strict reads to get back a filtered object where any fields not defined in the schema are not returned?

Because we have 30+ active fields and many inactive fields, it's important that we can define the schema once and then automatically filter the results. We do not want to duplicate the valid or invalid fields in multiple places. Note: Using a function like Object.keys on the schema to get an array of the valid fields and using that to filter is perfectly acceptable.


Solution

  • You can override the toJSON method using the transform function like this so that it doesn't have any fields not in the schema.

    const mongoose = require("mongoose");
    
    const LinkSchema = new mongoose.Schema({
      name: { type: String },
      style: { default: "icon", type: String }
    });
    
    var schemaFields = Object.keys(LinkSchema.paths);
    
    LinkSchema.set("toJSON", {
      transform: function(doc, ret, options) {
        let result = {};
        Object.keys(ret).map(key => {
          if (schemaFields.includes(key)) {
            result[key] = ret[key];
          }
        });
    
        return result;
      }
    });
    
    module.exports = mongoose.model("Link", LinkSchema);
    

    Update as @Loren mentioned in the comments, for the nested objects we can use Object.keys(LinkSchema.tree) instead of Object.keys(LinkSchema.paths).