MongoDB和Mongoose-创建自定义的,自动索引的辅助ID?

时间:2019-04-03 19:27:42

标签: node.js mongodb express mongoose indexing

我以通常的方式初始化数据库:

mongoose.connect(`mongodb://uname:pword@127.0.0.1:port/dbname?authSource=admin`, {useNewUrlParser: true, autoIndex: false});

我有一个架构,类似:

var materialSchema = new Schema({
    bookID: {type: String, required: true},
    active: Boolean,
    name: {type: String, required: true},
    stockLength: {type: Number, required: true}
});

module.exports = mongoose.model('material', materialSchema);

当我创建新材料并将其添加到数据库时,将自动为其分配通常的_id-这是我要维护的行为。但是,我也希望bookID是一个唯一的,自动递增的索引。这是用于物理架子存储,而不是用于查询或类似的东西。

我希望bookID通过以下方式递增:

A-001
A-002
A-003
...
A-098
A-099
A-100
B-001
...
B-100
...
Z-001
...
Z-100

如果上述模式不清楚,则该模式始于A-001,最后终止于Z-100。每个字母从001100,然后再移动到下一个字母。每个新集合条目只是该模式中的下一个ID。到达终点的可能性不大,但是到达终点时,我们将越过那座桥梁。

我只使用默认的_id进行索引,却不知道如何制作此模式。

感谢您的见解!

编辑#1

到目前为止,我想出的最好的解决方案是有一个单独的.txt文件,其中列出了所有ID。创建每个新对象时,将下一个ID从文件顶部弹出(...移位)。这还可能具有额外的好处,即以后可以轻松添加其他ID。这可能是我采用的方法,但是我仍然对上面要求的猫鼬解决方案感兴趣。

编辑#2

所以我认为我要使用的解决方案有些不同。基本上,findOnebookID降序排列。然后使用返回的值设置下一个。

Material.findOne()
    .sort({bookID : -1})
    .exec((err, mat) => {
        if(err) {
            // Send error
        }else if(!mat) {
            // First bookID
        }else {
            // Indexes exist...
            let nextId = getNextID(mat.bookID);

            // ...
        }
    });

仍然很容易修改getNextID()以在将来添加新的/不同的ID(如果/当到达“ Z100”时)

再次感谢!

1 个答案:

答案 0 :(得分:0)

好吧,所以要在 Edit#2 上进行一些扩展,我提出了以下解决方案。

在模型(模式)文件中,我们添加了一个schema pre() middleware,它在保存发生之前在调用.save()时执行:

// An arrow function will not work on this guy, if you want to use the "this" keyword
materialSchema.pre('save', function(next) {
    this.model('material').findOne()  // Don't forget the .model(...) bit!
        .sort({bookID : -1})  // All I need is the highest (i.e. most recent) bookID
        .select('bookID')  // Ditto above (not really necessary)
        .exec((err, result) => {
            if(err) {
                return next(err);  // Oopsies, an error!
            }else if(!result) {
                this.bookID = 'A-001';  // The case when collection is empty
            }else {
                this.bookID = getNextID(result.bookID);  // Otherwise, increment ID
            }

            next();  // Don't forget this sucker! This is how you save
        });
});

就是这样!它不是直接来自Mongoose的内置解决方案,但可以解决问题。

仅出于完整性考虑,getNextID函数如下所示:

function getNextID(curID) {
    let letter = curID.split('-')[0];
    let number = parseInt(curID.split('-')[1]);

    if(number >= 100) {  // Increase the letter and reset the number
        letter = String.fromCharCode(letter.charCodeAt(0) + 1)
        number = '001';
    }else { // Only increase the number
        number = ('' + (number + 1)).padStart(3, '0'); // Makes sure the numbers are always 3 digits long
    }

    return `${letter}-${number}`;
}

现在就做花花公子。直到我们到达Z100。但是,如果有的话,我会过桥。没什么大不了的。

并且您无需执行任何特殊操作即可使用它。只需照常保存一个新文档,它就会自动触发:

new Material({
    // New material properties
}).save((err, mat) => {
    // Handle errors and returns ...
});