Nick Parsons
Nick Parsons

Reputation: 8607

Mongoose Changing Schema Format

We're rapidly developing an application that's using Mongoose, and our schema's are changing often. I can't seem to figure out the proper way to update a schema for existing documents, without blowing them away and completely re-recreating them from scratch.

I came across http://mongoosejs.com/docs/api.html#schema_Schema-add, which looks to be right. There's little to no documentation on how to actually implement this, making it very hard for someone who is new to MongoDB.

I simply want to add a new field called enabled. My schema definition is:

var sweepstakesSchema = new Schema({
    client_id: {
        type: Schema.Types.ObjectId,
        ref: 'Client',
        index: true
    },
    name: {
        type: String,
        default: 'Sweepstakes',
    },
    design: {
        images: {
            type: [],
            default: []
        },
        elements: {
            type: [],
            default: []
        }
    },
    enabled: {
        type: Boolean,
        default: false
    },
    schedule: {
        start: {
            type: Date, 
            default: Date.now
        },
        end: {
            type: Date,
            default: Date.now
        }
    },
    submissions: {
        type: Number,
        default: 0
    }
});

Upvotes: 39

Views: 34070

Answers (7)

Carl A
Carl A

Reputation: 21

I had a similar requirement of having to add to an existing schema when building an app with Node, and only found this (long ago posted) query to help.

The schema I added to by introducing the line in the original description of the schema and then running something similar to the following line, just the once, to update existing records:

myModelObject.updateMany( { enabled : { $exists : false } }, { enabled : false } )

'updateMany' being the function I wanted to mention here.

Upvotes: 2

Vickar
Vickar

Reputation: 953

Considering your Mongoose model name as sweepstakesModel, this code would add enabled field with boolean value false to all the pre-existing documents in your collection:

db.sweepstakesModel.find( { enabled : { $exists : false } } ).forEach(
    function (doc) {
        doc.enabled = false;
        db.sweepstakesModel.save(doc);
    }
)

Upvotes: 24

Ahmed Gamaleldin
Ahmed Gamaleldin

Reputation: 51

You might use mongo shell to update the existing documents in a specific collection

db.SweeptakesModel.update({}, {$set: {"enabled": false}}, {upsert:false, multi:true})

Upvotes: 2

adir abargil
adir abargil

Reputation: 5745

just addition to what Vickar was suggesting, here Mongoose Example written on Javascript (Nodejs):

const mongoose = require('mongoose');
const SweeptakesModel = mongoose.model(Constants.SWEEPTAKES,sweepstakesSchema);
SweeptakesModel.find( { enabled : { $exists : false } }).then(
function(doc){
       doc.enabled = false;
       doc.save();
    }
)

Upvotes: 0

Janac Meena
Janac Meena

Reputation: 3567

I had the exact same issue, and found that using findOneAndUpdate() rather than calling save allowed us to update the schema file, without having to delete all the old documents first.

I can post a code snippet if requested.

Upvotes: 4

blablabla
blablabla

Reputation: 1478

I was also searching for something like migrations, but didn't find it. As an alternative you could use defaults. If a key has a default and the key doesn't exist, it will use the default.

Mongoose Defaults

Default values are applied when the document skeleton is constructed. This means that if you create a new document (new MyModel) or if you find an existing document (MyModel.findById), both will have defaults provided that a certain key is missing.

Upvotes: 4

JohnnyHK
JohnnyHK

Reputation: 311865

There's nothing built into Mongoose regarding migrating existing documents to comply with a schema change. You need to do that in your own code, as needed. In a case like the new enabled field, it's probably cleanest to write your code so that it treats a missing enabled field as if it was set to false so you don't have to touch the existing docs.

As far as the schema change itself, you just update your Schema definition as you've shown, but changes like new fields with default values will only affect new documents going forward.

Upvotes: 23

Related Questions