按顺序编号MongoDB子文档

时间:2015-04-12 15:50:34

标签: mongodb

我有一个MongoDB系列"部门"每个部门都有一个"门票"的子集合。在旧的基于MySQL的系统中,我们通过计算现有记录并添加一个来为每个票证(每个部门)分配一个号码。

这为每个部门提供了一个人类可读的编号系统来识别门票:1,2,3等。

然而,在Mongo中,没有使用像这样的自动增量字段,而且我发现由于操作可能是异步的(在NodeJS应用程序中使用Mongoose),计算现有记录可能不值得信任(相同)增加部门集合上的计数器)

我花了很多时间寻找解决方案,但却发现难以理清不相关的主题。

是否有任何可靠的方法来建立依赖于自定义查询的序号系统?

以下是我玩弄

的模特/保存代码示例
var OrganizationSchema = new Schema({
    name: {
        type: String,
        required: true
    },
    departments: [Department.schema]
});
var DepartmentSchema = new Schema({
    name: {
        type: String,
        required: true
    }
});

// Tickets aren't stored as subdocuments in Departments because there could be
// a lot, I didn't want it to affect performance
var TicketSchema = new Schema({
    project: {
        type: [{ type: Schema.Types.ObjectId, ref: 'Department' }],
        required: true
    },
    summary: {
        type: String,
        required: true
    }
});


// in-progress save code
Organization.findOne({ 'departments._id': department }, function(err, org){

    var lastTicketId = org.departments[0].lastTicketId;
    console.log(lastTicketId);

    var ticket = new Ticket({
        department: department,
        summary: req.body.summary
    });

    ticket.save(function(err, result) {

        if (err) {
            return next(err);
        }

        Organization.findOneAndUpdate(
            { 'departments._id': department },
            { $inc: { 'departments.$.lastTicketId': 1 } },
            function(err, result) {
                console.log('saving ' + result.departments[0].lastTicketId);
            }
        );
    });
});

此保存代码是API端点,因此我对来自for循环的20个API请求进行批量测试。这意味着他们的速度非常快,我真的可以看到编号的异步效应。

console.log输出为:

loading 0
loading 0
saving 0
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
saving 1
saving 2
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
loading 1
saving 3
saving 4
saving 9
saving 5
saving 10
saving 6
saving 11
saving 7
saving 12
saving 17
saving 8
saving 13
saving 18
saving 23
saving 14
saving 19
saving 24
saving 15
saving 20
saving 25
saving 16
saving 21
saving 22

3 个答案:

答案 0 :(得分:0)

mongoDB有两种可能的技术

  1. 计数器集合
  2. 乐观循环
  3. see mongoDB article here:

    本文中未提及的是计数器的集合保证了多进程环境中的唯一增量ID,但如果此id用于插入,则插入顺序不能100%保证与此id对应。 如果插入顺序很重要,请使用乐观循环技术

答案 1 :(得分:0)

如果您使用的是Mongoose,可以尝试自动增加:https://www.npmjs.com/package/mongoose-auto-increment

var OrganizationSchema = new mongoose.Schema({
    ...
});
var DepartmentSchema = new mongoose.Schema({
    ...
});

var TicketSchema = new Schema({
    ticketNumber: { type: Number, required: true },
    project: {
        type: [{ type: Schema.Types.ObjectId, ref: 'Department' }],
        required: true}],
    ...
});

TicketSchema.plugin(autoIncrement.plugin, {model: 'Ticket', field: 'ticketNumber'} );  

每次插入故障单文档时,这将自动增加ticketNumber。虽然每个部门没有增加 - 每张票只有一个唯一的号码。

最新的票号存储在MongoDB mongoose-auto-increments的特殊文档集中,因此即使您处于Web服务器多服务器情况下也不会出现选择下一个号码的问题。

虽然手动插入Ticket文档但要小心。您还需要手动更新mongoose-auto-increments集合。

答案 2 :(得分:0)

最后,这个问题有点不正确,因为我认为mongo是个问题。但是,在查看我发布的日志时,我意识到最终数字正在递增,所以我的问题必须是一个javascript问题。

我认为查询最后一个ID,然后保存票证,然后更新最后一个ID效率太低,但必须允许异步查询重叠。

我决定重写保存逻辑以验证票证而不保存它,然后在单个查询中递增最后一个ID,然后使用正确的值保存问题。

到目前为止它似乎完美无缺。

// Ensure validation passes before we increment an ID
// so we avoid disconnected IDs if it fails later
ticket.validate(function(err) {
    if (err) {
        return next(err);
    }

    // Find and update last ID in one transaction
    // due to async issues
    Organization.findOneAndUpdate(
        { 'departments._id': department },
        { $inc: { 'departments.$.lastTicketId': 1 } },
        function(err, result) {
            if (err) {
                return next(err);
            }

            ticket.displayId = result.departments[0].lastTicketId;
            ticket.save(function(err, user) {
                if (err) {
                    return next(err);
                }
                // success
            });
        }
    );
});