Mongooseでauto incrementの実装


最近、MongooseというMongoDB用のODM(Object Document Mappar)を使っているのですが、連番のID(0, 1, 2, 3…)のようにauto incrementさせることができるフィールドがデフォルトでは用意されていないみたい(そもそもMongoDBにその機能がない)なので、実装する方法を調べました。

解決方法としては単純なのですが(auto increment管理用のcollectionを作って、値を参照すると同時に+1していく)、Mongooseの仕様がちょこちょこと変わっているみたいなので他のブログにあるコードではそのまま動かなかったりと・・・ちょっと手こずりました。
参考:Has Mongoose support findAndModify Mongodb method?
下記のソースはMongoose V3.6.11では動いています。

 





// Mongoose使う時のお約束
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/DB名');
var Schema = mongoose.Schema;

// Counterスキーマを定義
// Counterは_idで複数個管理できる。
var counterSchema = new Schema({
_id: String,
seq: Number
});

// Counterスキーマに新しいIDを発行させるメソッドを追加
// MongoDBのfindAndModifyを用いて参照とともにカウンターの値を+1する。
// staticsに追加したメソッドは、クラスメソッドのような感覚で使える。
counterSchema.statics.getNewId = function (name, callback) {
return this.collection.findAndModify(
{ _id: name }, //Query
[], //sort
{ $inc: { seq: 1 } }, //update document
{ new: true, upsert: true }, //options
callback
);
};

// モデルを作成
var Counters = mongoose.model('counters', counterSchema);

...

// 使用する場合
Counters.getNewId('カウンタ名', function(err, counter){
if (err) throw err;
//呼び出すごとにseqが+1ずつされていく
var newId = counter.seq;
...
});


ポイントとしてはMongoDBにあるfindAndModifyのメソッドを使用しているところです。このメソッドはDB内のデータを参照すると同時に更新させることができます。updateの{ $inc: { seq: 1 } }で、seqというフィールドを+1ずつ更新しろと命令をだしていることになります。

またfindAndModifyはoptionsの指定により多少挙動が変わります。
今回は下記のように指定しています。

new:true …更新後の値を取得。
upsert:true…コレクション内に指定したフィールド(この場合カウンタ名)が無い場合はupdateの内容で新規作成する。


この場合、idは0から始まるようにできないのですが、MongoDBに手動でseq : 0を設定し、new:をfalseにすれば0から始めることができると思います。

MongoDBにもauto incrementデフォルトで用意してくれればいいのに。。。