猫鼬自动增量

HMR*_*HMR 19 javascript auto-increment mongoose mongodb

根据这篇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;
      }
    }
});
Run Code Online (Sandbox Code Playgroud)

我在同一个数据库中创建了计数器集合,并添加了一个_id为'entityId'的页面.从这里我不知道如何使用mongoose更新该页面并获得递增的数字.

计数器没有架构,我希望它保持这种方式,因为这实际上不是应用程序使用的实体.它只应在模式中用于自动增量字段.

edt*_*ech 39

以下是如何在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();
    });
});
Run Code Online (Sandbox Code Playgroud)

  • @realisation`findByIdAndUpdate`根据http://mongoosejs.com/docs/api.html#model_Model.findByIdAndUpdate发出一个_is_ atomic的mongodb`searchAndModify`. (3认同)
  • 您能告诉我当有多个并发请求时您的解决方案是否有效?如果是的话怎么办? (3认同)
  • 我意识到这有点旧了但是,当你对entitySchema做任何更新时(例如更新状态),这不会增加计数器,使得对uniqe id的所有引用都无用吗?也许先检查一下是新的. (3认同)
  • 你可以在声明 Schema 后把它放在同一个文件中 (2认同)

moo*_*ara 29

你可以使用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);
Run Code Online (Sandbox Code Playgroud)

你只需要初始化autoIncrement一次.

  • 该包不再维护。截至 2020 年 4 月,维护和记录得最好的 mongoose 自动增量包是 [`mongoose-sequence`](https://github.com/ramiel/mongoose-sequence)。 (13认同)

小智 12

投票最多的答案不起作用.这是修复:

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;
    });
});
Run Code Online (Sandbox Code Playgroud)

选项的参数为您提供了更新的结果,如果它不存在,它会创建一个新文档.你可以在这里查看官方文档.

如果您需要排序索引,请检查此文档

  • `findByIdAndUpdateAsync` **不是** Mongoose 文档中的方法。甚至答案中的链接也指向“findByIdAndUpdate”。 (2认同)

Tig*_*ran 7

我结合了答案中所有(主观和客观)好的部分,并提出了以下代码:

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

// Add a static "increment" method to the Model
// It will recieve the collection name for which to increment and return the counter value
counterSchema.static('increment', async function(counterName) {
    const count = await this.findByIdAndUpdate(
        counterName,
        {$inc: {seq: 1}},
        // new: return the new value
        // upsert: create document if it doesn't exist
        {new: true, upsert: true}
    );
    return count.seq;
});

const CounterModel = mongoose.model('Counter', counterSchema);


entitySchema.pre('save', async function() {
    // Don't increment if this is NOT a newly created document
    if(!this.isNew) return;

    const testvalue = await CounterModel.increment('entity');
    this.testvalue = testvalue;
});
Run Code Online (Sandbox Code Playgroud)

这种方法的好处之一是所有与计数器相关的逻辑都是独立的。您可以将其存储在单独的文件中,并将其用于导入CounterModel.

如果要增加该_id字段,则应在架构中添加其定义:

const entitySchema = new mongoose.Schema({
    _id: {
        type: Number,
        alias: 'id',
        required: true,
    },
    <...>
});
Run Code Online (Sandbox Code Playgroud)


Sim*_*mon 6

我知道这已有很多答案,但我会分享我的解决方案,这是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();
    }
});
Run Code Online (Sandbox Code Playgroud)

确保entitySchema._idtype:Number.猫鼬版:5.0.1.

  • 如果某些文档在某些时候被删除了,IMO会中断...但无论如何,它也适用于我的用例 (6认同)

Aka*_*wal 6

因此,结合多个答案,这就是我最终使用的内容:

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;
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)


PAL*_*SAI 5

这个问题已经足够复杂,并且有足够多的陷阱,最好依赖经过测试的猫鼬插件。

http://plugins.mongoosejs.io/上的大量“自动增量”插件中,维护和记录得最好的(而不是分叉)是mongoose sequence