Meteor-managed Ids Won't Play Nicely With Others
I am working with a data dump from a meteor project, and while retrieving and displaying the existing collection was no problem at all, I was stuck on saving new documents to mongo.
My schema was pretty straightforward and taken directly from an existing document:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
The problem was that last field:
_id. If I included it in the schema then I would have the objectId available on the front end but would get an error trying to insert a new document:
[Error: document must have an _id before saving]. If I removed
_id from the schema I could save documents just fine but could not pass through the objectIds of already existing documents. I have learned that mongo is very flexible when it comes to assigning ids before insertion into the database.
Mongo objects created through a meteor application are given meteor-friendly objectIds, the uniqueness of which is monitored and maintained by a meteor wrapper class. The design decision to go with ids as strings seems to be motivated by meteor’s latency compensation feature — creating documents on the client-side and then later syncing them with the server requires that they are assigned objectIds before they ever reach mongo. Mongo will accept a manually entered id, trusting that there is an entity somewhere that is managing uniqueness.
Here was my problem: the documents created by meteor had String ids assigned by meteor. If I included
_id in my schema, mongo would assume that I was managing id assignment manually, and wouldn’t save the object until I did. If I did not include
_id in my schema, mongo would assume it was responsible, and would assign a unique id accordingly.
To make the documents created by meteor play nice with the new stack, I had to update each document’s
_id with one created by mongo. Unfortunately, mongo won’t allow modification of
_id directly, so the only choice was to recreate and insert each entry, then delete the original:
- Retrieve a document:
doc = db.posts.findOne()
- Save the title:
title = doc.title
- Save the document’s string id:
id = doc._id
- Reassign the document id:
doc._id = ObjectId()
- Save the updated document:
- Remove the original document:
- Verify that the post exists with the new id:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
Here is a handy script for changing the entire collection at once: