我有一个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
答案 0 :(得分:0)
mongoDB有两种可能的技术
本文中未提及的是计数器的集合保证了多进程环境中的唯一增量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
});
}
);
});