How to define a nested schema in mongoose? - node.js

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.

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_

What is an equivalent work around to $setOnInsert in mongoose

I have below collection structure in mongodb. Say
Collection - student - _id,firstname,lastname,class
Now I want to insert 2 extra columns say marks as array{mark1:m1,mark2:m2}when inserting a newrow`.
I did it as below but it inserted record excluding marks values.
var student=new Student({
_id:id,
firstname:result.fname,
lastname:result.lname,
class:result.class,
marks:{
mark1:result.mark.m1,
mark2:result.mark.m2
}
})
Is this possible in Mongoose?
I came across $setOnInsert, but not sure whether this fits here?
So if it fits, is there any equivalent workaround to use MongoDb's $setOnInsert? if not what approach I could use?
Yes, it's possible but that depends on the options set when defining your schema. You don't necessarily need to use the $setOnInsert operator when inserting a new record, the save() method on the model suffices.
The strict option ensures that values added to your model instance that were not specified in the schema gets saved or not to the db.
For example, if you had defined your schema like this:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var studentSchema = new Schema({
firstname: String,
lastname: String,
class: String
})
var Student = mongoose.model('Student', studentSchema);
var student= new Student({
_id: id,
firstname: result.fname,
lastname: result.lname,
class: result.class,
marks: {
mark1: result.mark.m1,
mark2: result.mark.m2
}
});
student.save(); // marks is not saved to the db
But if you set the strict option to false:
var studentSchema = new Schema({..}, { strict: false });
var student= new Student({
_id: id,
firstname: result.fname,
lastname: result.lname,
class: result.class,
marks: {
mark1: result.mark.m1,
mark2: result.mark.m2
}
});
student.save(); // marks is now saved to the db!!
NOTE: The strict option is set to false in mongoose v2 by default for backward compatibility. Set it to true and sleep peacefully. Do not set to false unless you have good reason.

Nested Documents in Mongoose

I have two Mongoose schemas, User and Code. Each user can have many codes.
user.js:
var mongoose = require('mongoose');
var codeSchema = require('./code');
var userSchema = mongoose.Schema({
google: {
id: String,
token: String,
email: String,
name: String
},
codes: [codeSchema]
}, {collection : 'users'});
code.js:
var mongoose = require('mongoose');
var codeSchema = mongoose.Schema({
code: String,
name: String,
link: String
}, {collection: 'codes'});
module.exports = codeSchema;
My problem is, whenever I access a user's array of codes by user.codes, I get something like { _id: 56c4c82a37273dc2b756a0ce },{ _id: 56c4c82a37273dc2b756a0cd } rather than the JSON for a code.
What am I missing?
You're missing populate.
By default, Mongoose will only give you the _ids of any references made in a document. populate allows you to fill out nested documents.
userSchema.findOne({}).populate('codes');
More here
please check that you are inserting other values or not this can be a case . Please write how you are inserting in array . I have two other way check out
There are two way to do this
1-->either you save refrence id of codeschema and
2--> is you can insert whole codeschema in array
1. codes: {
type: mongooseSchema.ObjectId,
ref: 'codeSchema',
required: true
},
and when all data is in array 56c4c82a37273dc2b756a0ce,56c4c82a37273dc2b756a0cd
that can be done by this query
domain.User.update({_id:id}
,{$addToSet:{code:codeObjvalue}},
function(err,res){});
and then populate them by this
domain.users.find({},'code')
.populate('code','code color email').
exec(function(err,results){
callback(err, results);
});
2-- and second is to insert whole code schema in userschema
create a codeschema object and add in set like this
var codeobj={};
codeobj.code="xyz";
codeobj.email="xyz#gmail.com"
var codeobject = new domain.code(codeobj);
domain.User.update({_id:id},{$addToSet:{code:codeobject}},function(err,user1){
});
Woops, turns out I was using the wrong dataset, not adding the codes properly (facepalm). Thanks to everyone who answered!

Plugin usage with nested subdocuments in mongoose

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?

Why was mongoose designed in this way?

I'm new to mongoose,
If I want to define a model, I could use the following:
var ArticleSchema = new Schema({
_id: ObjectId,
title: String,
content: String,
time: { type: Date, default: Date.now }
});
var ArticleModel = mongoose.model("Article", ArticleSchema);
But why not just code like this:
var ArticleModel = new Model({
// properties
});
Why was mongoose designed in this way? Is there any situation where I can reuse "ArticleSchema"?
It's designed that way so that you can define a schema for subdocuments, which do not map to distinct models. Keep in mind that a there is a one-to-one relation between collections and models.
From the Mongoose website:
var Comments = new Schema({
title : String
, body : String
, date : Date
});
var BlogPost = new Schema({
author : ObjectId
, title : String
, body : String
, buf : Buffer
, date : Date
, comments : [Comments]
, meta : {
votes : Number
, favs : Number
}
});
var Post = mongoose.model('BlogPost', BlogPost);
Yeah sometimes I split the Schema's up into separate files and do this kind of thing.
// db.js
var ArticleSchema = require("./ArticleSchema");
mongoose.Model("Article", ArticleSchema);
It's only really useful when you have a bunch of static and other methods on models and the main model file gets messy.

Resources