web-dev-qa-db-ja.com

マングースの自動インクリメント

このmongodbの記事 によると、フィールドを自動インクリメントすることが可能であり、カウンタコレクションの方法を使用したいと思います。

この例の問題は、mongoコンソールを使用してデータベースにデータを入力する何千人もいないことです。代わりに、マングースを使用しようとしています。

したがって、私のスキーマは次のようになります。

var entitySchema = mongoose.Schema({
  testvalue:{type:String,default:function getNextSequence() {
        console.log('what is this:',mongoose);//this is mongoose
        var ret = db.counters.findAndModify({
                 query: { _id:'entityId' },
                 update: { $inc: { seq: 1 } },
                 new: true
               }
        );
        return ret.seq;
      }
    }
});

同じデータベースにカウンターコレクションを作成し、_entityIdの_idを持つページを追加しました。ここからは、mongooseを使用してそのページを更新し、増分番号を取得する方法がわかりません。

カウンター用のスキーマはありません。これは、アプリケーションで使用されるエンティティではないため、そのままにしておきたいと思います。スキーマでのみ使用して、フィールドを自動インクリメントする必要があります。

17
HMR

以下は、Mongooseで自動インクリメントフィールドを実装する方法の例です。

var CounterSchema = Schema({
    _id: {type: String, required: true},
    seq: { type: Number, default: 0 }
});
var counter = mongoose.model('counter', CounterSchema);

var entitySchema = mongoose.Schema({
    testvalue: {type: String}
});

entitySchema.pre('save', function(next) {
    var doc = this;
    counter.findByIdAndUpdate({_id: 'entityId'}, {$inc: { seq: 1} }, function(error, counter)   {
        if(error)
            return next(error);
        doc.testvalue = counter.seq;
        next();
    });
});
38
edtech

次のようにmongoose-auto-incrementパッケージを使用できます。

var mongoose      = require('mongoose');
var autoIncrement = require('mongoose-auto-increment');

/* connect to your database here */

/* define your CounterSchema here */

autoIncrement.initialize(mongoose.connection);
CounterSchema.plugin(autoIncrement.plugin, 'Counter');
var Counter = mongoose.model('Counter', CounterSchema);

autoIncrementを初期化する必要があるのは一度だけです。

28
moorara

最も投票された回答は機能しません。これは修正です:

var CounterSchema = new mongoose.Schema({
    _id: {type: String, required: true},
    seq: { type: Number, default: 0 }
});
var counter = mongoose.model('counter', CounterSchema);

var entitySchema = mongoose.Schema({
    sort: {type: String}
});

entitySchema.pre('save', function(next) {
    var doc = this;
    counter.findByIdAndUpdateAsync({_id: 'entityId'}, {$inc: { seq: 1} }, {new: true, upsert: true}).then(function(count) {
        console.log("...count: "+JSON.stringify(count));
        doc.sort = count.seq;
        next();
    })
    .catch(function(error) {
        console.error("counter error-> : "+error);
        throw error;
    });
});

optionsパラメーターは更新の結果を提供し、存在しない場合は新しいドキュメントを作成します。 こちら 公式ドキュメントを確認できます。

ソートされたインデックスが必要な場合は、これを確認してください doc

12
cluny85

これにはすでに多くの答えがあることはわかっていますが、IMOの短くてわかりやすいソリューションを共有します。

// Use pre middleware
entitySchema.pre('save', function (next) {

    // Only increment when the document is new
    if (this.isNew) {
        entityModel.count().then(res => {
            this._id = res; // Increment count
            next();
        });
    } else {
        next();
    }
});

entitySchema._idtype:Number。マングースバージョン:5.0.1

6
Simon

したがって、複数の答えを組み合わせて、これは私が最終的に使用したものです:

counterModel.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

const counterSchema = new Schema(
  {
  _id: {type: String, required: true},
  seq: { type: Number, default: 0 }
  }
);

counterSchema.index({ _id: 1, seq: 1 }, { unique: true })

const counterModel = mongoose.model('counter', counterSchema);

const autoIncrementModelID = function (modelName, doc, next) {
  counterModel.findByIdAndUpdate(        // ** Method call begins **
    modelName,                           // The ID to find for in counters model
    { $inc: { seq: 1 } },                // The update
    { new: true, upsert: true },         // The options
    function(error, counter) {           // The callback
      if(error) return next(error);

      doc.id = counter.seq;
      next();
    }
  );                                     // ** Method call ends **
}

module.exports = autoIncrementModelID;

myModel.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

const autoIncrementModelID = require('./counterModel');

const myModel = new Schema({
  id: { type: Number, unique: true, min: 1 },
  createdAt: { type: Date, default: Date.now },
  updatedAt: { type: Date },
  someOtherField: { type: String }
});

myModel.pre('save', function (next) {
  if (!this.isNew) {
    next();
    return;
  }

  autoIncrementModelID('activities', this, next);
});

module.exports = mongoose.model('myModel', myModel);
5
Akash Agarwal

プラグイン(server.jsで使用するものとは別にmongodb接続を初期化するなど)を使用したくないので、追加のモジュールを作成し、任意のスキーマで使用できます。さらに、DBからドキュメントを削除する時期を検討しています。

module.exports = async function(model, data, next) {
    // Only applies to new documents, so updating with model.save() method won't update id
    // We search for the biggest id into the documents (will search in the model, not whole db
    // We limit the search to one result, in descendant order.
    if(data.isNew) {
        let total = await model.find().sort({id: -1}).limit(1);
        data.id = total.length === 0 ? 1 : Number(total[0].id) + 1;
        next();
    };
};

そして、それを使用する方法:

const autoincremental = require('../modules/auto-incremental');

Work.pre('save', function(next) {
    autoincremental(model, this, next);
    // Arguments:
    // model: The model const here below
    // this: The schema, the body of the document you wan to save
    // next: next fn to continue
});

const model = mongoose.model('Work', Work);
module.exports = model;

お役に立てば幸いです。

(これが間違っている場合は、教えてください。私はこれに関して何の問題も抱えていませんが、専門家ではありません)

2
Alberto Rubio

他の方法は、mongooseが提供する外部パッケージを使用できることです(理解しやすい)。

マングースシーケンスプラグイン

1
PALLAMOLLA SAI

@ cluny85と@edtechを併用しています。しかし、完了を完了しませんこの問題。

counterModel.findByIdAndUpdate({_id: 'aid'}, {$inc: { seq: 1} }, function(error,counter){ただし、関数 "pre( 'save ...)では、ドキュメントの保存後に更新カウンターの応答が終了します。したがって、カウンターをドキュメントに更新しません。

すべての回答をもう一度確認してください。ありがとう。

ごめんなさい。コメントを追加できません。私は初心者だからです。

0
nguyen.thom

文書にすでに_idフィールド(並べ替えなど)が含まれている場合でも、答えはシーケンスを増やすようです。これは、既存のドキュメントを「保存」して更新する場合に当てはまります。いや?

私が正しければ、this._id!== 0であればnext()を呼び出したいでしょう。

マングースのドキュメントは、これについてあまり明確ではありません。内部で更新タイプのクエリを実行している場合、pre( 'save'は呼び出されない場合があります。

明確化

更新時に「保存」事前メソッドが実際に呼び出されるようです。

シーケンスを不必要に増やしたいとは思わない。クエリがかかり、シーケンス番号が無駄になります。

0
mschwartz
var CounterSchema = Schema({
    _id: { type: String, required: true },
    seq: { type: Number, default: 0 }
});
var counter = mongoose.model('counter', CounterSchema);

var entitySchema = mongoose.Schema({
    testvalue: { type: String }
});

entitySchema.pre('save', function(next) {
    if (this.isNew) {
        var doc = this;
        counter.findByIdAndUpdate({ _id: 'entityId' }, { $inc: { seq: 1 } }, { new: true, upsert: true })
            .then(function(count) {
                doc.testvalue = count.seq;
                next();
            })
            .catch(function(error) {
                throw error;
            });
    } else {
        next();
    }
});
0

これが提案です。

モデルコレクションの最大値を保持する別のコレクションを作成する

const autoIncrementSchema = new Schema({
    name: String,
    seq: { type: Number, default: 0 }
});

const AutoIncrement = mongoose.model('AutoIncrement', autoIncrementSchema);

必要なschemaごとに、pre-save hook

たとえば、コレクション名をTestとします

schema.pre('save', function preSave(next) {
    const doc = this;
    if (doc.isNew) {
         const nextSeq = AutoIncrement.findOneAndUpdate(
             { name: 'Test' }, 
             { $inc: { seq: 1 } }, 
             { new: true, upsert: true }
         );

         nextSeq
             .then(nextValue => doc[autoIncrementableField] = nextValue)
             .then(next);
    }
    else next();
 }

findOneAndUpdateatomic操作であるため、2つの更新が同じseq値を返すことはありません。したがって、同時挿入の数に関係なく、挿入ごとに増分seqが取得されますまた、これはより複雑な自動増分ロジックに拡張でき、自動増分シーケンスはNumbertype

これはテスト済みのコードではありません。 mongooseのプラグインを作成するまで、使用する前にテストしてください。

Updatethis プラグインは関連するアプローチを実装していることがわかりました。

0
MASh