What's the best practice (or tool) for updating/migrating Mongoose schemas as the application evolves?
3 Answers
It's funny though, MongoDB was born to respond to the schema problems in RDBMS. You don't have to migrate anything, all you have to do is set the default value in the schema definition if the field is required.
new Schema({
name: { type: string }
})
to:
new Schema({
name: { type: string },
birthplace: { type: string, required: true, default: 'neverborn' }
});

- 4,447
- 1
- 25
- 23
-
1I'm really thinking about tools like Rails' migrations which let you handle the change management aspects, but I don't think there really is anything like it, so I'll accept this. – mahemoff Jan 07 '12 at 21:33
-
I know what you mean but I don't see a utility for that in document based databases or am I wrong? If you keep your schemas under a source control like Mercurial/Subversion/git, you can always revert to previous revisions. – vimdude Jan 09 '12 at 02:17
-
5I don't think it's so different to SQL databases. You might be splitting "name" into "firstname" and "surname" fields for example...you'd have to run that transformation against each environment's database and track it somehow. – mahemoff Jan 09 '12 at 11:56
-
Yes but you don't have to "migrate". In RDBMS, you have to migrate. – vimdude Jan 12 '12 at 04:38
-
20You don't have to "migrate" the schema (well sort of, you might still migrate indexes etc in the absence of an actual schema), but you *do* have to migrate the actual data. – mahemoff Jan 12 '12 at 11:55
-
I've already ran into several cases where I need to migrate existing data. – chovy Oct 29 '12 at 06:19
-
@chovy can you share more info on that? – vimdude Oct 29 '12 at 13:40
-
1I'm adding a field that is required and populated on .save(), and none of the existing data has it yet. So I need to call save() on all of them to get it. We need a way to migrate data this way for express/mongoose apps. – chovy Oct 29 '12 at 17:58
-
2You're trying to fix history. You should use plugins instead. – vimdude Oct 29 '12 at 22:19
-
So, any solution to this? I've also run into data migration woes. – Joe Apr 06 '13 at 20:10
-
3Ok, i have a me too, as I don't have this situation yet, but I have a VERY large schema that I know will need to change over time, so how do I access items in a collection that were created in a previous version of the schema? Is there magic in mongoose? – regretoverflow May 03 '13 at 19:44
-
@Zlatko i don't follow – chovy Mar 26 '15 at 20:41
-
I mean, this way you still do not have this property set on all docs, until the first save. If you just do an update and set that DoB to 'neverborn' to all, you're clear. – Zlatko Mar 27 '15 at 09:26
-
@vimdude how do you solve this problem in mongodb if i have already have the production without having any default value set http://stackoverflow.com/questions/36697070/mongodb-schema-changes-results-in-error-for-old-users?noredirect=1#comment60982632_36697070 – santhosh Apr 19 '16 at 06:32
-
See my comment on that link. You can add version to your structure. – vimdude Apr 19 '16 at 14:27
-
To clarify, for my understanding, if you `find()` on a property that doesn't exist for some documents, will this throw an error, or will those documents simply be excluded from the results? – Ryan Griggs Dec 31 '19 at 14:58
I just had this problem where I needed to update my database to reflect the changes to my schema. After some research I decided to try the updateMany() function in the mongo console to make the updates and I think it worked pretty well.
To apply this to vimdude's example the code would look as follows:
try {
db.<collection>.updateMany( { birthplace: null }, { $set:
{"birthplace": "neverborn" } } );
} catch(e) {
print(e);
}
The updateMany() function will update all documents in a collection based on a filter. In this case the filter is looking for all documents where the field 'birthplace' is null. It then sets a new field in those documents named 'birthplace' and sets its value to 'neverborn'.
After running the code, modified to reflect your circumstances run:
db.<collection>.find().pretty()
to verify that the changes were made. The new field "birthplace" with the value of "neverborn" should show at the end of each document in your collection.
Hope that helps.

- 5,495
- 3
- 19
- 29

- 566
- 5
- 12
Update: Tested, this does not work in its current form, its got the right idea going, I got a single migration to work with considerable tweaking of the module itself. But I don't see it working as intended without some major changes and keeping track of the different schemas somehow.
Sounds like you want mongoose-data-migrations
It is intended to migrate old schema versions of your documents as you use them, which is seems to be the best way to handle migrations in mongodb.
You don't really want to run full dataset migrations on a document collection (ala alter table) as it puts a heavy load on your servers and could require application / server downtime. Sometimes you may need to write a script which simply grabs all documents applies the new schema / alterations and calls save, but you need to understand when/where to do that. An example might be, adding migration logic to doc init has more of a performance hit than taking down the server for 3 hours to run migration scripts is worth.
I found this link pretty helpful as well, basically reiterates the above in more detail and essentially implements the above node package's concept in php.
N.B. The module is 5months old, 0 forks, but am looking around and can't find anything better / more helpful than abdelsaid's style of response..

- 4,371
- 3
- 39
- 54
-
1Updated. Sadly its rather broken. Let me know here if you ever find anything, kind of want a suitable solution for the update as you go method. I have a feeling you'd need to keep track of each version in order to load older schemas and allow modifications like the module attempts to do. Alas, my mongoose knowledge is pretty lacking so far. Getting there! – lsl Feb 27 '14 at 11:12