is it possible to reference a subdocument schema in mongoose? - node.js

is it possible to reference a sub document schema in mongoose ?
just like below
var sectionSchema = mongoose.Schema(
{
id:{type:String,required:true},
name:{type:String,required:true}
});
var courseSchema = mongoose.Schema(
{
id:{type:String,required:true},
name:{type:String,required:true},
sections:[sectionSchema]
});
var studentSchema = mongoose.Schema(
{
id:{type:String,required:true},
name:{type:String,required:true},
course:{type:mongoose.Schema.Types.ObjectId,ref: 'courseSchema'},
section:{type:mongoose.Schema.Types.ObjectId,ref: 'sectionSchema'},
contactnumber:{type:String,required:true},
parentname:{type:String,required:true}
});
var schoolSchema = mongoose.Schema(
{
id:{type:String,required:true},
name:{type:String,required:true,unique:true},
address:{type:String,required:true},
year:{type:String,required:true},
contactnumber:{type:String,required:true},
courses:[courseSchema],
students:[studentSchema]
});
var School = mongoose.model('School',schoolSchema);
in the above model i have section inside course which is inside school document.
i have students schema which is inside school document i want course to point to course schema and section to point to section schema.so is it possible to refer a sub document schema in mongoose.

Related

How do I update the existing documents' schema?

I'm using mongoose to do some MongoDB operations.
At the beginning the category was number,
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const sampleSchema = new Schema({
category: {
type: Number,
}
})
module.exports = mongoose.model("SampleSchema", sampleSchema);
Now the category changed to String, So I changed the model like this
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const sampleSchema = new Schema({
category: {
type: String,
}
})
module.exports = mongoose.model("SampleSchema", sampleSchema);
The problem is, I have already inserted 200 records into this collection. Is there any way to update the category value with a string and change its type to string?
Please get All data by query and update it one by one in loop.
Like:
db.tableName.find( { 'status' : { $type : 1 } } ).forEach( function (val) {
val.status = new String(val.status);
db.tableName.save(val);
});
I changed the category to mixed, that's working fine with numbers and string.
Thanks for the help #prasad_

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.

Accessing subdocument properties in mongoose

I am using a MEAN stack to build this application.
Here is my subject.js schema:
var mongoose = require('mongoose');
var schema = mongoose.Schema;
var topics = require('./topic');
var subjectSchema = new schema({
_category : {
type: String,
default: ""
},
topics: [topics.schema]
});
module.exports = mongoose.model('Subject', subjectSchema);
and my topics.js schema:
var mongoose = require('mongoose');
var schema = mongoose.Schema;
var otherstuff = require('./otherstuff');
var otherstuff2 = require('./otherstuff2');
var topicSchema = new schema ({
title: String,
otherstuff: [mongoose.model('otherstuff').schema],
otherstuff2: [mongoose.model('otherstuff2').schema]
});
module.exports = mongoose.model('Topic', topicSchema);
What I am having difficulty with is how to access my topicSchema to populate it with forms from my front end.
I can save information to the subjectSchema, but not the sub documents.
I have tried using this as outlined in another article:
var Subject = mongoose.model('Subject', subjectSchema);
Subject.find({}).populate('subjects[0].topics[0].title').exec(function(err, subjects) {
console.log(subjects[0].topics[0].title);
});
But I continue to get TypeError: Cannot read property 'title' of undefined. How do I access the title property?
populate in mongoose is used to populate referenced documents, that are marked with ref attribute (see more info in the docs). Sub-documents on the other hand are available when do a simple query because they are actually an array of custom objects, so if you remove the populate method your query will work as expected:
Subject.find({}).exec(function(err, subjects) {
console.log(subjects[0].topics[0].title);
});

Mongoose Sub-documents on separate files, how to embed them

I'm defining my application models and i have separate files for each model that i'm defining, my question is, i need to create a model that use a sub-document, but that's on another file, how can i use that Schema on my model ? what i mean is that all examples i've seen declare the Child model and the Parent on the same file, example:
var childSchema = new Schema({ name: 'string' });
var parentSchema = new Schema({
children: [childSchema]
});
I have one file called user.js that defines the user model :
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
_id : Schema.Types.ObjectId,
username : String,
});
module.exports = mongoose.model( 'User', userSchema );
And on another file called sport.js i have the other model definition for the sports:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var sportSchema = new Schema({
_id : Schema.Types.ObjectId,
name : String
});
module.exports = mongoose.model( 'Sport', sportSchema );
So on my user model I need to define a field for the sports that the user will follow, but i do not know how to define that sub-document since the sports definition is on another file, I tried this:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var SportsModel = require('sport');
var userSchema = new Schema({
_id : Schema.Types.ObjectId,
username : String,
sports : [SportsModel]
});
module.exports = mongoose.model( 'User', userSchema );
But i'm not sure if that's the correct way since what i'm exporting is the model, not the Schema.
Thanks in advance, i want to define each model on separate files to maintain order.
You can access a Model's schema via its schema property. So this should work:
var userSchema = new Schema({
_id : Schema.Types.ObjectId,
username : String,
sports : [SportsModel.schema]
});
Use ref
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
_id : Schema.Types.ObjectId,
username: String,
sports : [{ type: Schema.Types.ObjectId, ref: 'Sport' }]
});
module.exports = mongoose.model('User', userSchema);
Incidentally, with ref, you can use .populate('sports') when you query, and mongoose will expand those types for you.

Resources