Reputation: 21
I am looking for a way to shorten the ObjectID generated by the MongoDB database, and I am aware of some of the existing library like 'shortid''short-mongo-id'
However, my problem is that I wish to create a new 'shortID' field in the mongoose schema for every document that exists in the collection, and this new field should be unique and ideally the truncated version of the ObjectId attached to the document. Like such:
var subjectSchema = new Schema({
shortID: {required: true, unique: true},
//must be unique to each document and is same everytime server restarts
Sex: {type: String, enum: enumSex},
Diagnosis: String,
Projects:[projectPerSubjectSchema]
});
The 'shortid' https://www.npmjs.com/package/shortid library works good and does generate unique id, but, it generates different id every time server restarts, which is not what I want.
Another library I tried 'short-mongo-id' https://www.npmjs.com/package/short-mongo-id was able to convert ObjectId into a truncated version of unique ID string, however, I'm not sure how to use it in creating a schema. I've tried:
ID: {type: String, 'default': shortid((this.ObjectId).valueOf()), unique: true}
to try and get the document's ObjectId using this.ObjectId, stringify it with valueOf(), but the terminal shows:
TypeError: Cannot read property 'valueOf' of undefined
All of the code are done in Node.JS and I am very new to both NodeJS and MongoDB, so please correct me if I am making some major errors with the code provided above. Thanks in advance!
Upvotes: 2
Views: 2457
Reputation: 179
The shortid module should work for what you need, you just need to save the shortId as normal String field, and make sure a new code is generated before saving, like this (inside mongoose schema definition):
const mongoose = require('mongoose')
const shortid = require('shortid')
const Schema = mongoose.Schema
const schema = new Schema({
_shortId: {
type: String,
unique: true
},
... // other fields...
})
// This is for checking if the document already have a _shortId,
// so you don't replace it with a new code
schema.pre('save', function (next) {
let doc = this
if (!this._shortId) {
addShortId(doc, next)
}
})
function addShortId (doc, next) {
let newShortId = shortid.generate()
doc.constructor.findOne({_shortId: newShortId}).then((docRes) => {
if (docRes) {
addShortId(doc, next)
} else {
doc._shortId = newCode
next()
}
}, (err) => {
next(err)
})
}
If you want to insert a _showId for all the existing documents, you just need a forEach
and save the model again, this is how I'm doing (using https://github.com/JMPerez/promise-throttle, cause it's a huge collection, calling save() all at once would slow down the server) :
XXXXX.find({ '_shortId': { '$exists': false } }).then((data) => {
var promiseThrottle = new PromiseThrottle({
requestsPerSecond: 50,
promiseImplementation: Promise
})
var i = 1
data.forEach(element => {
var myFunction = function (j) {
return element.save()
}
promiseThrottle.add(myFunction.bind(this, i++)).then(ss => {
console.log('done ' + ss._shortId)
})
})
Some of this code is adapted from: https://github.com/dylang/shortid/issues/65
Upvotes: 1