Why the name of the Model is Capitalized.
As in their documentation, they have capitalized it.
var schema = new mongoose.Schema({ name: 'string', size: 'string' });
var Tank = mongoose.model('Tank', schema);
Why is Tank capitalized here? Is there any specific reason?
Sorry if this is not a good question. Any help would be appreciated :)
This is merely a coding convention. The Tank model is being viewed as an instantiable class:
var small = new Tank({ size: 'small' });
According to typical coding conventions, class names should be UpperCamelCase with the first letter capitalised, and instance variables should be in lowerCamelCase (as should methods).
Reference Mongoose Documentation
var schema = new mongoose.Schema({ name: 'string', size: 'string' });
var Tank = mongoose.model('Tank', schema);
The first argument is the singular name of the collection your model
is for. ** Mongoose automatically looks for the plural, lowercased
version of your model name. ** Thus, for the example above, the model
Tank is for the tanks collection in the database.
Related
I'm having trouble wrapping my head around the below syntax in a mongoose schema.
tokens:[{
token:{
type: 'String',
required: true
}
}]
Normally when I want to add objects to arrays I would just push the object. That includes if I want to push an object with an internal object to said array like the example below.
let obj =[]
obj.push({name: 'dirk', age: 24})
obj.push({name: 'chris', age:29, clothes: {shirt: 'black', pants: 'jeans'}, height: '6ft'})
So im confused in mongoose as to why I need this syntax [{}] to use an array?
Ok I'll try to explain this as best I can. In basic JavaScript, an array is just a bucket of "stuff" for lack of better words. What that means is, you could have something like this:
let myList = []
myList.push({name: "John Doe", age: 20})
myList.push({car: {make: "Honda", model: "Accord"}})
myList.push({menu_items: ["item 1", "item 2", "item 3"]})
And JavaScript won't really care right? As far as it's concerned, you haven't done anything wrong because you technically did the correct thing, put some object into a list that can hold whatever you want.
Mongoose, which is an ORM (check out the term if you haven't heard of it before), requires things be a little more strict. Remember that Mongoose is trying to map documents from the Mongo database to this "Object" that should be standard and readable from any point in the code the same what. So in the example in your question listed above:
tokens:[{
token:{
type: 'String',
required: true
}
}]
you are saying to Mongoose that it should expect tokens to contain a list of token objects that have a certain design to them. Now, when you want to add more token objects to the tokens list, you can do something like this:
token = {
// YOUR CORRECT TOKEN DATA
}
tokens.push(token);
If you tried to do something like this instead:
token = {
// RANDOM WRONG DATA
}
tokens.push(token);
Mongoose wouldn't take kindly to it because you are violating the constraints you told Mongoose to keep in affect. If you start throwing any: [{}] into the mix, you are telling Mongoose that any old object will do for that list. This is, in my opinion, very dangerous to do because if you have two types of objects in your list:
var schema1 = new Schema({
name: String,
age: { type: Number, min: 18, max: 65 },
living: Boolean
})
var schema2 = new Schema({
name: String,
age: { type: Number, min: 18, max: 65 },
breed: Boolean
})
and you were working with a list that combined these two objects, if you tried to grab say breed from the schema1 type object, you would either get an error or an odd value that could break your code. So Mongoose strictly types the objects you are pushing to a list, unless you use something like Mixed or any. Here's a link to the documentation that may help explain a bit as well
https://mongoosejs.com/docs/schematypes.html#arrays
If this doesn't make sense or I explained it poorly or answered the wrong question please comment and I'll fix it to explain as best I can.
Happy coding :-)
I have the following mongodb / mongoose Schema
var forumReplySchema = new Schema({
userid : String,
username: String,
forumid: {type: String, default: '1'},
message: {type: String, default: ''},
time: Number,
});
module.exports = mongoose.model('forum_replies', forumReplySchema);
with following query:
forum_replies.findOne({forumid: forumid}).then(function (reply) {
currentReply.username = user.username;
currentReply.rank = result.rank;
});
Currently username is assigned cause i have username property in the Schema.
Rank is not assigned cause its not in the Schema.
But is there a way for me to assign rank, without having it defined in the Schema?
Edit: aka, assign rank to the forum replies object without the need to save in Db.
you cannot add properties to mongoose document. If you want to do so, you will need to convert it into plain object first. There are couple of ways you could go about it. Following is one of them.
reply.toObject();
Then you can add properties to it.
//you have currentReply in your code, I just want to show general idea here
reply.rank = result.rank;
Is this what you are looking for?
Update:
Thanks for accepting answer :). Also look into lean() option, this returns you plain JS objects without you having to do the conversion manually. lean() also has performance benefit.
While debugging a mongoose callback I found out that either underscore.js or the JavaScript language itself seems to have a problem with big numbers.
In the example below, I store a small number, and a String that contains an ObjectId from mongoose (24 digit number), in order to show the problem as clearly as possible.
var users = ["32", "300000000000000000000002"];
alert(_.contains(users, "32")); // true
alert(_.contains(users, (32).toString())); // true
alert(_.contains(users, "300000000000000000000002")); // true
alert(_.contains(users, (300000000000000000000002).toString())); // false - wait wat ?
My question is, of course, how to make the last call return true ?
I would prefer not to convert the array users to an array of numbers, because (1) the array might be huge in a production context, and (2) I may need to do other operations on the array.
The last returns "3e+23" which is not equals to "300000000000000000000002"
The problem was always that I get an input String which is automatically converted to a number (by a library). So I only had to make the 'foreign key' a smaller number. I eventually created a custom number autogenerate function to circumvent this problem:
var autoIncrement = require('mongoose-auto-increment');
var address = require('./Address');
var connection = mongoose.createConnection(address.mongo());
autoIncrement.initialize(connection);
var UserSchema = new mongoose.Schema({ /* property definitions */});
mongoose.model('User', UserSchema);
UserSchema.plugin(autoIncrement.plugin, {
model: 'User',
startAt: 10000001
});
As a result, I had to change the referencing mechanism:
var GroupSchema = new mongoose.Schema({
users: [{type: Number, ref: 'User'}],
/* other property definitions */
});
At a high level, I'm looking to remove a document from Mongo as well as its referenced documents. Take a look at the following example Schemas:
var studentSchema = mongoose.Schema({
email: String,
name: String,
_class: { type: String, ref: 'Class' },
books: [{ type: Schema.Types.ObjectId, ref: 'Book' }]
});
module.exports = mongoose.model('Student', studentSchema);
var classSchema = mongoose.Schema({
gradeLevel: Number,
students: [{ type: Schema.Types.ObjectId, ref: 'Student' }]
});
module.exports = mongoose.model('Class', classSchema);
var bookSchema = mongoose.Schema({
author: String,
subject: String,
pages: Number
});
module.exports = mongoose.model('Book', bookSchema);
Now, my question is two fold:
1. If I want to .remove() a Class document from my database AND all Student documents referenced to it, what is the best way of doing this? //currently looping through students with the given class id and individually removing, then finally removing the class document.
2. If I want to .remove() a Class document from the db AND all Students AND their Books, is there a way to do this simply through a special remove statement in mongo? //Currently finding all students, removing their books, then remove themselves, then remove their referenced class.
Ideally, I would like a statement the can remove a mongo document, and anything referenced to it, along with any sub-references that sub-document may have. (e.g: Remove a Class and have mongo auto-remove all Students and their Books) Is this possible?
there is no statement that does what you want in mongoDb or mongoose. MongoDB is not the best choice if such operations that span multiple collections are very important for your application ("no automatically supported joins and referential integrity in MongoDB"). You also might need to model your data more "mongo-like" to achieve what you want.
You can do it more efficiently than looping if you have backreferences. The model.find() function returns a query object, that has a .remove(cb) method
mongooose.model('Student').find({_class: myClassToRemove._id}).remove(function(err) {});
For your books this will not work, because Book does not have a reference to Student. But if you do not share books between different students, then you should just store the books within the student object as "embedded documents" instead of using a different model and references. Then they will be deleted automatically when you delete a student.
If you do share one book instance between multiple students, you can not automatically delete the book when you delete a student, because you don't know whether another student uses the same book instance.
Below is my Schema.
var UserModel = new Schema({
id: ObjectId
, email: String
, firstName: String
, lastName: String
, password: String
});
var MessageModel = new Schema({
id: ObjectId
, createdDate: { type: Date, default: Date.now }
, user: String // should this be [UserModel]?
, body: String
});
For my case, every message has a user but only one. Should I Embed UserModel or should I leave the user field as a string. One future use case would be to return a query that has the body of the message, creation date, and user (first name and last name concatenated). Thanks.
Short answer: No, you should not use the UserModel as a subdocument of MessgeModel.
Long answer: First, reconsider your naming. You are actually defining schemas here. Later, you will be associating a model with each of these schemas. So, UserSchema and MessageSchema would be more appropriate here.
But that's not germane. Regarding your question, you're MessageModel schema should not contain embedded documents representing users unless there is a 1-to-1 relationship. However, I expect that each user will be associated with many messages (hopefully). So, you don't want a new copy of the user (each with a new _id) for every message he creates. You only want one canonical document for each user, and a reference to that user in the MessageModel.
Now, using a string reference may be the right choice for you. But if you anticipate running a query on the MessageModel in which you'd like the user attribute to be populated by the actual UserModel document, then you'll want to use a ref.