Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose and MongoDB, out of sync with relationships

Am I missing something ? Why does it take more effort in ORM's to syncronize relationships compared to traditional databases. Take the following for example .

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

The UserSchema has many Events where the event schema belongs to one user aka creator.

.delete(function(req, res){
        Event.remove({
            _id:req.params.event_id
        },function(err,response){
            if(err)
                res.send(err);
            res.json({message:'Successfully Deleted'});
        });
    });

If I create a event and add the user object as the creator, it successfully joins the tables but if I delete the event. The Event no longer shows but the ID still shows under the User query.

Below is what my user query looks like after I delete event that belongs to the user

[
  {
    "_id": "5831be814f8df40646fed954",
    "password": "$2a$10$MNbwpj0qi9.rhEPmCHe5mOc8crrEo/CwbxVSbjjLSw28GdcQ0O6Um",
    "username": "klaus",
    "__v": 1,
    "events": [
      "5831c216a3d6810692bdf381"
    ]
  }
]

How would I go about removing that ID from the Users Schema ? Is it better to not link the Events Schema with the Users Schema ? Why is this a pain in the ass and why is this the future ?

like image 488
numerical25 Avatar asked Nov 21 '16 14:11

numerical25


1 Answers

This is not an ORM, there are no joins and there are no tables. You are trying to use Mongo like it was a relational database, which it isn't.

Answering your question "Why is this a pain in the ass and why is this the future?" - Unless you recognize Mongo as a document store and use it as such, you will always be disappointed.

Now, some background. In a relational database you can have foreign keys, constraints and triggers that can make sure that you either cannot remove a tuple when it is referenced in another relation or you can remove it but the operation cascades and removes the references that would now point to a nonexistent key and cause database inconsistency. This is also usually done in one transaction so you can be sure that no one will see an inconsistent view of the data.

With Mongo there are no such guarantees. There are validations but those can be bypassed.

When you store a reference to another document it is just a String or an ObjectId instance that doesn't have to exist in the database anywhere. "References provides more flexibility than embedding. However, client-side applications must issue follow-up queries to resolve the references. In other words, normalized data models can require more round trips to the server." (see Normalized Data Models) In other words, not only the validity of relationships is not enforced, the actual "joining" takes place on the client side, not in the database, in a separate query (with possible race conditions).

Additionally you have no transactions so it's not possible to remove a document and all references to it in one atomic operation. But even if it was possible, there is still no schema in Mongo so whenever you have an ObjectId as a value of some field, Mongo doesn't know which collection is it supposed to be referring to so it wouldn't even know where to look for.

It means that you need to clean up manually after removing data that can possibly be referenced in another document. But since the database will not tell you where the ObjectId of the document that you're removing could possibly be stored, you are responsible for knowing that and making sure that you keep the database consistent yourself.

Now, for the schemas. There is really no concept of a schema in Mongo. There are schemas in Mongoose but not in Mongo. "Data in MongoDB has a flexible schema. Collections do not enforce document structure." (see Data Modeling) Having that "flexible schema" just means having no schema at all. In practice the schemas only exist in the client-side in Mongoose. You can have a great Mongoose schema but if you have more than one application connecting to the same database (or even two versions of the same application) then those applications can have inconsistent schemas and can silently corrupt your database.

Taking it all into considerations, I would advice to use Mongo only when you don't need guaranteed consistency, transactions, foreign keys, joins, enforced schemas and other features that you may be familiar with when working with other databases, or otherwise it will always be a pain as you described it.

like image 170
rsp Avatar answered Oct 13 '22 00:10

rsp