Mongoose: Remove Document and all references completely - node.js

I was wondering. I have a lot of coding to do with a function to remove a document from the database. Basically removing just the object is not that much work, but removing the _id reference from all the other models step by step in the right order is the big work load (I pushed the object ID into the other objects so I could create relations and populate later).
I was wondering: is there no function standard in mongoose that instantly removes the document as well as all its objectId references in the documents of the other model types (so completely remove the object and all it's ObjectID references in all the other collections in the DB)?

You can achieve what you are looking for using this NPM package called
cascading-relations here

Related

How to delete Items in MongoDB / Mongoose & make sure to not end up with non-referenced objects in my DB?

How do I delete an Document in MongoDB, which references other Documents?
Say I want to delete a book: The book has an author which it references, and also a table of contents which is a reference. Now when I delete the book, I will want to delete the table of contents for sure, but maybe not the author, since the same author might have written different books which are still in my database and are referencing this author, so I don't want to delete this.
But then the author object to-be-deleted may itself reference other objects, and the table of contents object too. It seems extraordinarily complicated then, to delete a single item in mongoose / mongodb? Or am I not getting something? Is there an easier way?
Is there a way for example to delete all objects in a collections, that are not referenced by anything else?

How to modify array single subdocument without loading that entire array in-memory?

I'm using Node.js v8.12.0, MongoDB v4.0.4 & Mongoose v5.3.1.
I want to update an embedded array subdocument without changing its position in array index. And without loading the entire array in memory because that array might get very big in future.
I spent a lot of time searching how to achieve this but without luck.
I've tried to use Mongo's $elemMatch to load the document with only single relevant array subdocument, but that wouldn't let me save the subdocument in any practical way.
I've also looked into Mongoose array set method, but for this you need to have subdocument array index, so this mean I need to load the entire array into a memory and then find subdocument index.
Is there any way to achieve what I want? Ideally via Mongoose abstractions, so all Mongoose middleware like validations, plugins, etc. kick in.
Actually found the answer right after submitting this question.
For anyone looking it up in future, you can use special $ operator in combination with $set. (I'm not sure if that makes use of mongoose middlewares, though. I need to do some testing around that).
Here's some code example, which queries some subdocument using _id, and then updates that subdocument property someProperty using $set which uses special operator $ that matches queried subdocument array position/index.
var doc = await SomeModel.findOneAndUpdate(
{'someArray._id': 'xxx'},
{'$set': {'someArray.$.someProperty': 'someValue'}},
);
It's still not 100% what I'm looking for, though. Because the returned doc still has full array of subdocuments (I assume that's still loaded into memory?), and it seems that I can't use $elemMatch in combination with $set.
In my case, further down the road, I'll probably redesign the database schema so these embedded subdocuments will be their own documents with just ObjectID reference to "parent" document.
Some resources:
https://docs.mongodb.com/manual/reference/operator/update/positional/
https://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate

Saving a form part way through mongodb

I'm pretty new to MongoDB and best practices. I'm using Node full stack JS.
I created a form which spans multiple screens. This saves to a mongoose.model Schema and creates a document when the user submits the form.
I've been given the requirement to allow the user to save the form when part way through. The problem with trying to save to the existing Schema is I get a duplicate id reference error as I'm saving multiple fields as null which already exist in the Collection. Plus I'm thinking this is a waste of memory.
The answer is very simple it just took me some circular thinking to get to it. I check to see if properties are undefined before setting them. If they are undefined they are an empty value rather than null i.e. {} for an Object. Mongoose is ok with that, it just doesn't like null values (makes sense).

How does `mongoose` handle adding documents that have FIELDS that are __NOT__ part of the schema?

I'm playing around with quick start guide for mongoose.
http://mongoosejs.com/docs/index.html
I assumed that it would throw an error when I saved a document with a field NOT defined in the schema. Instead, it created a new document in the collection but without the field. (Note: I realize mongodb itself is "schema-less" so each document in a collection can be completely different from each other.)
two questions
How does mongoose handle adding documents that have fields that are NOT part of the schema? It seems like it just ignore them, and if none of the fields map, will create an empty document just with an ObjectId.
And how do you get mongoose to warn you if a specific field of a document hasn't been added even though the document successfully saved?
(The question is - I believe - simple enough, so I didn't add code, but I definitely will if someone requests.)
Thanks.
Q: How does mongoose handle adding documents that have fields that are NOT part of the schema?
The strict option, (enabled by default), ensures that values passed to our model constructor that were not specified in our schema do not get saved to the db.
- mongoose docs
Q: How do you get mongoose to warn you if a specific field of a document hasn't been added even though the document successfully saved?
The strict option may also be set to "throw" which will cause errors
to be produced instead of dropping the bad data. - mongoose docs
...but if you absolutely require saving keys that aren't in the schema, then you have to handle this yourself. Two approaches I can think of are:
1. To save keys that aren't in the schema, you could set strict to false on a specific model instance or on a specific update. Then, you'd need to write some validation that (a) the values in the document conformed to your standards and (b) the document saved in the database matched the document you sent over.
2. You could see if the Mixed schema type could serve your needs instead of disabling the validations that come with strict. (Scroll down to 'usage notes' on that link, as the link to the 'Mixed' documentation seems broken for the moment.)
Mongoose lets you add "validator" and "pre" middleware that perform useful functions. For instance, you could specify the required attribute in your schema to indicate that a specific property must be set. You could also specify a validator that you can craft to throw an error if the associated property doesn't meet your specifications. You can also set up a Mongoose "pre" validator that examines the document and throws an Error if it finds fields that are outside of your schema. By having your middleware call next() (or not), you can control whether you proceed to the document save (or not).
This question/response on stackoverflow can help with figuring out whether or not an object has a property.

Storing and retrieving JavaScript objects in/from MongoDB

I am currently playing around with node.js and MongoDB using the node-mongo-native driver.
I tested a bit around using the Mongo console storing and retrieving JS objects. I figured out, that if I store an object that contains functions/methods the methods and functions will also be stored in the collection. This is interesting since I thought that functions could not be stored in MongoDB (with the exception of the system.js collection, as suggested by the Mongo docs).
Also it will not only store the methods but actually each method and member of the object's entire prototype chain. Besides that I dont like this behaviour and think it's unintuitive I mustn't have it.
I was going to manage users in a Mongo collection. To do this I have a User object containing all of the users methods functioning as a prototype for each instance of an user. The user object itself would only contain the users attributes.
If I store a user in the Mongo collection I only want to store the own properties of the user object. No prototype members and especially no prototype methods. Currently I do not see how to cleanly do this. The options that I figured might work are:
creating a shallow copy using foreach and hasOwnProperty and storing this copy in the collection.
Add a data attribute to each user that contains all the object's attributes and can be stored in the collection.
This just came to my mind writing this: I could also set all the prototypes properties to not enumerable which should prevent them from being stored in the collection.
However, I do have the same issues the other way around: when loading a user from a collection. AFAIK there is no way to change an objects prototype in JavaScript after it was created. And there's also no way to specify a prototype to use when Mongo instantiates objects it retrieved from a collection. So basically I always get objects that inherit from Object using Mongo. As far as I can tell I have 2 options to restore a usable user object from this point on:
Create a fresh object inheriting from User and copying each attribute on the result object to the newly created object. (Compatible to storing mechanisms 1 & 3)
Create a fresh object inheriting from User and storing the result object as a data attribute on the newly created object. (Compatible to storing mechanism 2)
Are my assumptions, especially about the possibility to specify a prototype for query results, correct? What's the right way to do it, and why? I'm surely not the first person struggling to store and resurrect objects in/from MongoDB using node.js.
Currently I would go with the approach 2/2. I don't really like it, but it is the most efficient and the only one that works cleanly with the API. However, I'd much rather hear that actually the API does nothing wrong, but I do for not knowing how to use it correctly. So please, enlighten me :)
I just recently realized, that it actually is possible to change an objects prototype in V8/node. While this is not in the standard it is possible in various browsers and especially in V8/node!
function User(username, email) {
this.username = username;
this.email = email;
}
User.prototype.sendMail = function (subject, text) {
mailer.send(this.email, subject, text);
};
var o = {username: 'LoadeFromMongoDB', email: 'nomail#nomail.no'};
o.__proto__ = User.prototype;
o.sendMail('Hello, MongoDB User!', 'You where loaded from MongoDB, but inherit from User nevertheless! Congratulations!');
This is used all over various modules and plugins - even core modules make use of this technique, allthough it is not ECMAScript standard. So I guess it is safe to use within node.js.
I'm not sure I'm following you question exactly... but fwiw one thing came to mind: Have you checked out the Mongoose ORM? (http://mongoosejs.com/)
It gives you a lot of options when it comes to defining models and methods. In particular "Virtuals" might be of interest (http://mongoosejs.com/docs/virtuals.html).
Anyway, hope it helps some!

Resources