有一个用户课程预约的项目,因为后端有node来做,所以mongodb是个很好的选择,可是因为课程预约系统存在 用户预约成功后,或取消预约后,会有课程预约信息的事务操作,我对mongo的了解是她不适合用在事务场景里,我对数据库的设计不是很了解,想请问课程预约这样的项目适合用mongodb吗?
MongoDB不适合用于强事务的场景,但很多场景需要的往往不是真的强事务,而可以用最终一致性取而代之。很多强事务也可以通过数据模型设置的技巧转变成MongoDB的文档原子性从而避免强事务。你需要更清楚地描述你所说的事务到底是怎样的场景,才好判断是不是可以避免。对于我自己理解的课程预约场景来说,并不是一个很强的非MongoDB不可的场景,但也不是一个非RDBMS不可的场景。所以要说是不是适合用MongoDB,还是建议具体情况具体分析。=== 2017.4.9 更新 ===根据评论里的更新,做以下补充说明:限制人数这个需求来说可以用MongoDB的文档原子性来解决。我理解的报名这个场景来讲,无非是记录谁报了哪个课程,一共多少人报了,以及控制不要超报名限额。那么课程的数据结构可以设计成类似这样:
{ _id: ObjectId("58e9f6cd58d2c10959c8619a"), title: "MongoDB入门教程", intro: "演示用", createdAt: ISODate("2017-04-09T17:00:00Z"), createdBy: { userId: 12345, name: "MongoDB中文社区" // 其他必要的信息 }, allowedAttendeeQty: 50, // 允许参与的人数 reservations: { qty: 0, // 已预订人数 attendees: [123, 456, 789] // 参与人员ID } }
当有人报名时,可以对这个课程进行更新:
var result = db.class.findAndUpdate( query: { _id: ObjectId("58e9f6cd58d2c10959c8619a"), qty: {$lte: 50} // 保证已报名人数小于50时才报名 }, update: { $inc: { "reservations.qty": 1 // 报名人数+1 }, $push: { "reservations.attendees": 102 // 新报名人员ID } } });
也就是说,按照课程ID来查找这个课程,报名人数小于指定的数量时,会把新的报名人加进去,否则不会做任何更改。那么如何判断报名是否成功呢?findAndModify默认会返回修改之前的文档(也可以返回修改之后的文档)。所以:
findAndModify
if (result.reservations.qty < 50) { // 报名成功 } else { // 报名失败 }
关于findAndModify的用法请参考db.collection.findAndModify()。MongoDB中对一个文档的修改具备原子性,所以不难发现update也可以很好地完成上述任务。关于update和findAndUpdate的比较,可以参考:Compares with update Method
update
findAndUpdate
MongoDB不适合用于强事务的场景,但很多场景需要的往往不是真的强事务,而可以用最终一致性取而代之。很多强事务也可以通过数据模型设置的技巧转变成MongoDB的文档原子性从而避免强事务。你需要更清楚地描述你所说的事务到底是怎样的场景,才好判断是不是可以避免。
对于我自己理解的课程预约场景来说,并不是一个很强的非MongoDB不可的场景,但也不是一个非RDBMS不可的场景。所以要说是不是适合用MongoDB,还是建议具体情况具体分析。
=== 2017.4.9 更新 ===
根据评论里的更新,做以下补充说明:
限制人数这个需求来说可以用MongoDB的文档原子性来解决。我理解的报名这个场景来讲,无非是记录谁报了哪个课程,一共多少人报了,以及控制不要超报名限额。那么课程的数据结构可以设计成类似这样:
当有人报名时,可以对这个课程进行更新:
也就是说,按照课程ID来查找这个课程,报名人数小于指定的数量时,会把新的报名人加进去,否则不会做任何更改。那么如何判断报名是否成功呢?
findAndModify
默认会返回修改之前的文档(也可以返回修改之后的文档)。所以:关于
findAndModify
的用法请参考db.collection.findAndModify()。MongoDB中对一个文档的修改具备原子性,所以不难发现update
也可以很好地完成上述任务。关于update
和findAndUpdate
的比较,可以参考:Compares with update Method