我错过了什么吗?与传统数据库相比,为什么在ORM中需要花费更多精力来同步关系。以下面的例子为例。
var UserSchema = new Schema({
username: {type: String, required: true, index:{unique:true}},
password: {type: String, required: true},
events: [{type: Schema.Types.ObjectId, ref:'Event'}]
});
var EventSchema = new Schema({
_creator: {type:Schema.Types.ObjectId, ref: 'User'},
post: {type: String, required: true}
});
UserSchema有许多事件,其中事件架构属于一个用户又名创建者。
.delete(function(req, res){
Event.remove({
_id:req.params.event_id
},function(err,response){
if(err)
res.send(err);
res.json({message:'Successfully Deleted'});
});
});
如果我创建一个事件并将用户对象添加为创建者,则它会成功加入表,但是如果我删除了该事件。事件不再显示,但ID仍显示在用户查询下。
以下是我删除属于用户的事件后用户查询的内容
[
{
"_id": "5831be814f8df40646fed954",
"password": "$2a$10$MNbwpj0qi9.rhEPmCHe5mOc8crrEo/CwbxVSbjjLSw28GdcQ0O6Um",
"username": "klaus",
"__v": 1,
"events": [
"5831c216a3d6810692bdf381"
]
}
]
如何从用户架构中删除该ID?不将事件架构与用户架构链接是否更好?为什么这是一个痛苦的屁股,为什么这是未来?
答案 0 :(得分:3)
这不是ORM,没有连接,也没有表。您正在尝试使用Mongo,就像它是一个关系数据库,它不是。
回答你的问题"为什么这是一个痛苦的屁股,为什么这是未来?" - 除非您将Mongo视为文档存储并将其用作文档存储,否则您将永远感到失望。
现在,一些背景知识。在关系数据库中,您可以使用外键,约束和触发器,以确保您在另一个关系中引用元组时无法删除它,或者您可以删除它但操作级联并删除现在指向的元组不存在的密钥并导致数据库不一致。这通常也只在一个事务中完成,因此您可以确定没有人会看到数据的不一致视图。
对于Mongo,没有这样的保证。有validations,但可以是bypassed。
当您存储对另一个文档的引用时,它只是一个String或ObjectId实例,它不必在任何地方存在于数据库中。 "参考提供比嵌入更多的灵活性。但是,客户端应用程序必须发出后续查询以解析引用。换句话说,规范化数据模型可能需要更多往返服务器。" (参见Normalized Data Models)换句话说,不仅没有强制执行关系的有效性,而且实际的"加入"在客户端而不是在数据库中,在单独的查询中(具有可能的竞争条件)。
此外,您没有任何交易,因此无法在一次原子操作中删除文档及其所有引用。但即使有可能,Mongo中仍然没有模式,所以每当你将ObjectId作为某个字段的值时,Mongo都不知道它应该指的是哪个集合所以它不会甚至知道在哪里寻找。
这意味着您需要在删除可能在其他文档中引用的数据后手动清理。但是,由于数据库不会告诉您可能存储的文档的ObjectId可能存储在哪里,因此您有责任了解并确保自己保持数据库的一致性。
现在,对于模式。 Mongo中确实没有架构的概念。 Mongoose有模式,但Mongo没有模式。 " MongoDB中的数据具有灵活架构。集合不强制执行文档结构。" (见Data Modeling)拥有"灵活的架构"只是意味着根本没有架构。实际上,模式只存在于Mongoose的客户端。您可以拥有一个出色的Mongoose模式,但如果您有多个应用程序连接到同一个数据库(甚至同一个应用程序的两个版本),那么这些应用程序可能会有不一致的模式,并且可能会无声地损坏您的数据库。
考虑到这一点,我建议只在不需要保证一致性,事务,外键,连接,强制模式以及在使用其他数据库时可能熟悉的其他功能时才使用Mongo ,或者如你所描述的那样,它总会很痛苦。