Plugin usage with nested subdocuments in mongoose - node.js

I have a schema in mongoose like this:
var subtopicSchema = new schema({
name:String
})
var topicSchema = new schema({
name:String,
subtobpics:[subtopicSchema]
});
var subjectSchema = new schema({
name:String,
topics:[topicSchema]
})
var courseSchema = new schema({
name:{type:String,unique:true},
subjects:[subjectSchema]
});
And then I am using a 'unique validator plugin' like this:
courseSchema.plugin(uniqueValidator, { message: 'unique' });
So here is what i want to achieve:
All courses should be unique
All subjects within a particular course needs to be unique
All topics within a particular subject to needs be unique
All subtopics within a particular topic to needs be unique
So the question is: Is the current setup gonna work for the above four requirements?
If yes, why?
If not, How?

Related

Nested objects are not update

Allora, I'm using mongoose for the first time and I decided to create 2 schemes: the first one represents a user and the second one represents his enquires. Users have an array of enquires like:
var userSchema = new mongoose.Schema({
name: String,
enquires: { type : [Enquire.schema] , "default" : [] },
});
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
I see that if I search for an enquire and update its status, it doesn't update the same enquire on the user's array, meaning that they are different object. I don't want to save an array of IDs as it will be the same as a relational database, so I see only 1 solution which is forgetting about the enquire scheme and use only the User scheme. Is it the way mongoose works? For every relationship do I have to insert everything like nested object?
I think you should use references to achieve what you want to achieve.
For more information on mongoose references and populate see Mongoose Populate documentation.
Try this, It may help you.
User Schema :
var userSchema = new mongoose.Schema({
name: String,
enquires: [{ type : mongoose.Schema.Types.ObjectId , ref : 'Enquiry' }]//array of enquiries
});
var User = mongoose.model('User',userSchema );
module.exports = User;
Enquiry Schema :
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
var Enquiry = mongoose.model('Enquiry',enquireSchema );
module.exports = Enquiry ;
Working :
create a new Enquiry.
Push it's ID(_id) into user's enquires array.
var enquiry = new Enquiry();
enquiry.enquire = "Dummy enquiry";//set the enquiry
enquiry.save(function(err,result){
if(!err){
//push 'result._id' into users enquires array
}
});
whenever you update an enquiry, it will be automatically updated in
user's document.
use populate to retrieve user's enquiries.
You can embed sub documents (entity) which has id and is like a document or embed native array like a normal property.
And I think the correct definition for yours is :
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
var userSchema = new mongoose.Schema({
name: String,
enquires: { type : [enquireSchema] , "default" : [] },
});
If you use refs in embedded link then there are two separate collections and be like relational db's.

One-To-Many relation in MongoDB

At the moment I am looking at mongoDB. I try to implement a simple one-to-many relation using nodejs and mongoose:
Model/Schema User:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var UserSchema = new Schema({
name: String
});
module.exports = mongoose.model('User', UserSchema);
Model/Schema Article:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ArticleSchema = new Schema({
name: {
type: String,
required: true
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
module.exports = mongoose.model('Article', ArticleSchema);
So my question, now:
How can I get all Users including its Articles?
Do I really have to add a ref to my UserScheme, too? What is the best-practice in an one-to-many relation like this? Is there something like a join in mongodb?
One User has many Articles - an Article belongs to one User.
Calling something like /user/:user_id , I want to receive the user with _id=user_id containing all of his articles.
That is the most horrible idea, for various reasons.
First, there is a 16MB BSON document size limit. You simply can not put more into a document. Embedding documents is rather suited for "One-to-(VERY-)Few" relationships than for a "One-to-Many".
As for the use case: What is your question here? It is
For a given user, what are the articles?
REST wise, you should only return the articles when /users/:id/articles is GETed and the articles (and only the articles) should be returned as a JSON array.
So, your model seems to be natural. As for the user:
{
_id: theObjectId,
username: someString
…
}
and an article should look like this:
{
_id: articleIdOrSlugOrWhatever,
authors: [theObjectId],
// or author: theObjectId
retention: someISODate,
published: someOtherISODate
}
So when your REST service is called for /users/:id you'd simply look up
var user = db.users.findOne({_id:id})
And when /users/:id/articles is called, you'd lookup
var articles = db.articles.find({author:id})
Problem solved in a scalable way, adhering to REST principles.

Populating count of records from other collection with Mongoose

I have 2 Mongoose models, Book and Users. i want to do that: When find a book, i want to get the count of current book users.
this is book model:
var mongoose = require('mongoose');
var Users = require('../users');
var schema = new mongoose.Schema({
book_name: String,
book_publisher: String
});
var book = mongoose.model('book', schema);
module.exports = book;
this is users model:
var mongoose = require('mongoose');
var Book = require('../book');
var schema = new mongoose.Schema({
user_name: String,
book_id: String
});
var users = mongoose.model('users', schema);
module.exports = users;
i fetch a book like this:
Book.find({book_name:name).exec(
function(err, book) {
if (err) {
throw err;
}
var new_book = book;
}
);
right now tis code fetch a book, but i want to populate count of users inside Users model and add them to the new fetched book object.
i read this document but i can't accomplish that:
Population
User = new mongoose.Schema({
//existing user properties
owned_books: [{type: mongoose.Schema.Types.ObjectId, ref: 'book'}]
}}
var users = mongoose.model('users', User);
var schema = new mongoose.Schema({
book_name: String,
book_publisher: String,
owner_ids: [{type: mongoose.Schema.Types.ObjectId, ref: 'users'}]
});
var book = mongoose.model('book', schema);
You'll need to update both schema when you add people to books or books to people. To get the current book users, just find the book and then get length of it's owner_ids field.
What you want to do is usually known as reverse lookup. Luckily, someone has already created a module for that. It doesn't seem like its a very commonly used module, but you could see if it fits your needs: reverse-populate.

How to define a nested schema in mongoose?

My mongo record is like this:
{
"_id":{"$oid":"5550b6de437f572112a29f1a"},
"cv_count":177732,
"gender_info": {"male_count": 50, "female_count": 32}
"stability_info_list":[{"ratio":8.802558610369414e-05,"total_count":34081,"years":0},{"ratio":5.868372406912943e-05,"total_count":34081,"years":1}],
"zhineng_id":"IT Manager"
}
I write the schema like this:
var ZhinengGenderSchema = new Schema({
male_count: Number,
female_count: Number
});
var ZhinengStabilitySchema = new Schema({
ratio: Number,
total_count: Number,
years: Number
});
var ZhinengStats = new Schema({
cv_count: Number,
gender_info: ZhinengGenderSchema,
stability_info_list: [ZhinengStabilitySchema],
zhineng_id: String
})
But I got this excetion:
TypeError: Undefined type `undefined` at `gender_info`
Did you try nesting Schemas? You can only nest using refs or arrays.
so mongoose doesn't support nest schemas? But my database has already been there, I cannot change, so how can I define my schema?
Just don't create a new schema for the subdocuments and you should be fine, i.e.:
var ZhinengGenderSchema = {
male_count: Number,
female_count: Number
};
var ZhinengStabilitySchema = {
ratio: Number,
total_count: Number
years: Number
};
var ZhinengStats = new Schema({
cv_count: Number,
gender_info: ZhinengGenderSchema,
stability_info_list: [ZhinengStabilitySchema],
zhineng_id: String
})
With mongoose you can define nesting (embedded) schemas in Array, like this:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var bookSchema = new Schema({
value: { type: String }
});
var authorSchema = new Schema({
books: [bookSchema]
});
Or by reference
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = mongoose.Schema.Types.ObjectId;
var auhtorSchema = new Schema({
book: { type: ObjectId, ref: 'Book'}
});
You may choose what is more appropriate for you
As far as I know, this is due to a current limitation of Mongoose. You cannot
declare a schema field to include a single sub-document: you have to use an array, instead. See this: https://github.com/Automattic/mongoose/pull/585
You can set up later the proper business logic in order to ensure that only one sub-element will be added.
Try this:
var ZhinengStats = new Schema({
cv_count: Number,
gender_info: [ZhinengGenderSchema],
stability_info_list: [ZhinengStabilitySchema],
zhineng_id: String
})
This way, each sub-document has got its own _id in MongoDB (even though it does not lie in a specific collection). See more: http://mongoosejs.com/docs/subdocs.html
You could also prefer something like this:
var ZhinengStats = new Schema({
cv_count: Number,
gender_info: [{male_count: Number, female_count: Number}],
stability_info_list: [ZhinengStabilitySchema],
zhineng_id: String
})
In this case, you nest a schema inside another. The single gender_info element does not have the dignity of a document.

how to convert mongoose js model to object

i am working with node.js and mongoosejs framwork for mongodb. I am trying to convert a mongoose model to an object, I was able to do that, but am getting only fewer elements rather than getting all. Below code which I tried.
user.js
var schema = new Schema({
name:{ type:string },
title:{ type:string, default:"mr" }
});
module.exports = mongoose.model('Users', schema);
usermanager.js
var User = require(../user.js);
var user = new User();
console.log(user.toString());
//printed as {_id:2583457assda312, title:'mr'}
i am expecting name key in that object. i have also tryed toObject it also giveing me the same response.
ther is any posiblty to achive this?
Your usage is intended to be like this:
var user = new User({ name: "Fred" })
and you will get the values from what you have defined, so in this case:
//printed as {_id:2583457assda312, name: "Fred", title:'mr'}
Or you supply your title as here:
var user = new User({ name: "Wilma", title: "Ms" })
and again get your output
//printed as {_id:2583457assda312, name: "Wilma", title: "Ms"}
If what you are trying to do is inspect the schema there is a paths property on Mongoose schema objects
console.log( user.schema.paths )
And that should give you a definition of the various parts of the schema you defined.

Resources