猫鼬自动增量

问题描述 投票:15回答:10

根据this mongodb article,可以自动增加一个字段,我想使用计数器收集方式。

这个例子的问题是我没有成千上万的人使用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;
      }
    }
});

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

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

javascript mongodb mongoose auto-increment
10个回答
37
投票

以下是如何在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();
    });
});

0
投票
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();
    }
});

28
投票

您可以使用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一次。


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;
    });
});

选项参数为您提供更新结果,如果不存在,则创建新文档。你可以查看官方文件here

如果你需要一个排序索引检查这个doc


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();
    }
});

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


4
投票

所以结合多个答案,这就是我最终使用的:

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);

2
投票

我不想使用任何插件(一个额外的依赖,初始化mongodb连接除了我在server.js中使用的那个等等)所以我做了一个额外的模块,我可以在任何架构使用它甚至,我正在考虑从数据库中删除文档。

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;

希望它能帮到你。

(如果这是错的,请告诉我。我一直没有遇到任何问题,但是,不是专家)


1
投票

另一种方法是你可以使用mongoose给出的外部包。(易于理解)

mongoose sequence plugin


0
投票

即使文档已经有一个_id字段(排序,无论如何),答案似乎也会增加序列。如果您“保存”以更新现有文档,则会出现这种情况。没有?

如果我是对的,如果this._id!== 0,你想调用next()

猫鼬文件对此并不十分清楚。如果它在内部执行更新类型查询,则可能不会调用pre('save')。

澄清

似乎'save'pre方法确实在更新时被调用。

我不认为你想要不必要地增加你的序列。它会花费您查询并浪费序列号。


0
投票

我一起使用@ cluny85和@edtech。但我没有完成这个问题。

counterModel.findByIdAndUpdate({_id: 'aid'}, {$inc: { seq: 1} }, function(error,counter){ 但是在函数“pre('save ...)中,然后更新计数器的响应在保存文档之后完成。所以我不更新计数器到文档。

请再次检查所有答案。谢谢。

抱歉。我无法添加评论。因为我是新手。

© www.soinside.com 2019 - 2024. All rights reserved.