how can i exit nodejs script after mongo db write - javascript

I have 400,000 lines to enter and I need to break it up. Unfortunately I cannot get this script to exit until it's completed everything. It invariably runs out of memory of course. I thought setting a value at .on('end',function() would be useful but I can't see that value once the .on data has completed.
'use strict';
var mongoose = require('mongoose');
var fs = require('fs');
var parse = require('csv-parse');
var Schema = mongoose.Schema;
var done;
mongoose.connect('mongodb://127.0.0.1:27017/auth');
var userSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
password: String,
email: {
type: String,
unique: true
},
isActive: String,
roles: {
account: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Account'
}
},
timeCreated: {
type: Date,
default: Date.now
},
search: [String]
});
var accountSchema = new mongoose.Schema({
user: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
name: {
type: String,
default: ''
}
},
isVerified: {
type: String,
default: ''
},
verificationToken: {
type: String,
default: ''
},
name: {
first: {
type: String,
default: ''
},
middle: {
type: String,
default: ''
},
last: {
type: String,
default: ''
},
full: {
type: String,
default: ''
}
},
company: {
type: String,
default: ''
},
phone: {
type: String,
default: ''
},
zip: {
type: String,
default: ''
},
memberid: {
type: String,
default: ''
},
status: {
id: {
type: String,
ref: 'Status'
},
name: {
type: String,
default: ''
},
userCreated: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
name: {
type: String,
default: ''
},
time: {
type: Date,
default: Date.now
}
}
},
userCreated: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
name: {
type: String,
default: ''
},
time: {
type: Date,
default: Date.now
}
},
search: [String]
});
var User = mongoose.model('User', userSchema);
var Account = mongoose.model('Account', accountSchema);
fs.createReadStream('./ipart')
.pipe(parse({
delimiter: ','
}))
.on("data-invalid", function(data) {})
.on('data', function(csvrow) {
var u = {
isActive: 'yes',
username: csvrow[0],
email: csvrow[0],
search: [
csvrow[1] + ' ' + csvrow[2],
csvrow[0],
]
};
User.create(u, function(err, createdUser) {
if (err) {
console.log(err);
return;
}
var user = createdUser;
var displayName = csvrow[1] + ' ' + csvrow[2] || '';
var nameParts = displayName.split(' ');
var acct = {
isVerified: 'no',
'name.first': nameParts[0],
'name.last': nameParts[1] || '',
'name.full': displayName,
user: {
id: user._id,
name: user.username
},
search: [
nameParts[0],
nameParts[1] || ''
]
};
Account.create(acct, function(err, account) {
if (err) {
return workflow.emit('exception', err);
}
var fieldstoset = {
roles: {
account: account._id
}
};
User.findByIdAndUpdate(account.user.id, fieldstoset, function(err, user) {
if (err) throw err;
});
});
});
})
.on('end', function() {
console.log('complete');
});

You really need to use bulk inserts, I found this code somewhere and pasting it for you
var Potato = mongoose.model('Potato', PotatoSchema);
var potatoBag = [/* a humongous amount of potato objects */];
Potato.collection.insert(potatoBag, onInsert);
function onInsert(err, docs) {
if (err) {
// TODO: handle error
} else {
console.info('%d potatoes were successfully stored.', docs.length);
}
}

I would recommend you to break down your entire logic of importing your CSV data into these following steps:
1. Write a simple script file which imports the CSV into a temporary collection like this:
YourImportScript
#!/bin/bash
mongoimport -d YourDBName -c YourTempCollectionName --drop --type csv --file pathToYourCSVFile.csv --headerline
2. Run the scripts before creating your Users:
var exec = require('child_process').exec;
function importCSV(callback) {
exec("./pathToYourImportScript/YourImportScript", function (error, stdout, stderr) {
console.log(stdout);
if (error !== null)
console.log('exec error: ' + error);
});
callback()
}
MongoImport will import the CSV pretty quickly.
Get the documents from the temp collection and insert them into your Users Collection.
You can also use async module to control the flow of your code mode neatly:
async.series([
function (callback) {
//CSV Import function
},
function (callback) {
//User Manupulation function
}]);
And it is better to put headers into your CSV columns, as you can create a model when importing documents from the temp collections, and it would be easier to get the properties of users by column headers like username:myCSVModel.username instead of username: csvrow[0].

Related

Mongoose updateMany for array of array

Currently, I am working on a project on academic management of the university, every semester students will get marks for training and if someone is below 50/100 they will receive a warning email. I use mongoose, namely mongo atlas to store data, expressjs for backend, I create a model called "classes" to define the information of classes as follows:
const mongoose = require('mongoose')
const classSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
consultant: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Consultant',
required: true
},
classname: {
type: String,
required: true,
unique: true
},
studentList: [
{
code: {
type: String,
required: true
},
fullname: {
type: String,
required: true
}
}
]
})
const Class = mongoose.model('Class', classSchema)
module.exports = Class
and this my model of student:
const mongoose = require('mongoose')
const studentSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
fullname: {
type: String
},
code: {
type: String,
required: true,
unique: true
},
classname: {
type: String,
require: true
},
gender: {
type: String,
required: true,
enum: ['Male', 'Female', 'No Record'],
default: 'No Record'
},
birthday: {
type: String
},
vnumail: {
type: String,
unique: true,
required: true,
match: /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/
},
vnumail: {
type: String,
match: /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/
},
profileImage: {
type: String,
default:
'https://kittyinpink.co.uk/wp-content/uploads/2016/12/facebook-default-photo-male_1-1.jpg'
},
hometown: {
type: String
},
accademicTrainningList: [
{
score: {
type: Number,
required: true
},
schoolYear: {
type: String,
required: true
},
semester: {
type: String,
required: true,
enum: ['1', '2'],
default: '1'
},
classification: {
type: String,
required: true,
enum: [
'Excellent',
'Good',
'Intermediate',
'Average',
'Weak',
'Fail',
'No Record'
],
default: 'No Record'
}
}
],
scoreList: [
{
score: {
type: Number,
required: true
},
subjectCode: {
type: String,
required: true
},
subjectName: {
type: String,
required: true
}
}
],
receiveScholarship: [
{
scholarshipName: {
type: String,
required: true
},
value: {
type: Number,
required: true
}
}
],
prizeList: [
{
constestName: {
type: String,
required: true
},
ranking: {
type: Number,
required: true
}
}
],
scienceContestPrizeList: [
{
constestName: {
type: String,
required: true
},
ranking: {
type: Number,
required: true
}
}
],
wentAbroad: [
{
country: {
type: String
},
time: {
type: Date
}
}
],
tookTheTest: [
{
testName: {
type: String,
required: true
},
ranking: {
type: Number,
required: true
}
}
],
punishList: [
{
studentCode: {
type: mongoose.Schema.Types.ObjectId
}
}
]
})
studentSchema.pre('save', function (error, doc, next) {
if (error.name === 'MongoError' && error.code === 11000) {
next(new Error('There was a duplicate key error'))
} else {
next()
}
})
const Student = mongoose.model('Students', studentSchema)
module.exports = Student
I then create a route to add a new class and The input is a .xlsx file and I will extract the information in that file and add the properties of the xlsx file and add it to the database. I use the xlsx - npm library to extract the information and save it. this image demonstrate my input file
router.post(
'/',
upload.single('excel'),
extract_data,
add_new_class,
add_students_from_excel,
add_parent_from_excel,
add_user_from_excel
)
This is the middleware I use to extract the information:
const xlsx = require('xlsx')
const { formatClassname } = require('../../helpers')
exports.extract_data = (req, res, next) => {
let { file } = req
let workbook = xlsx.readFile(file.path)
const sheet_name_list = workbook.SheetNames
let { classname, schoolYear, semester } = req.body
data = []
sheet_name_list.forEach(sheet => {
let workSheet = workbook.Sheets[sheet]
let dataArr = xlsx.utils.sheet_to_json(workSheet)
dataArr.forEach(info => {
var fullname = info['Họ tên ']
var code = info['Mã SV ']
var birthday = info['Ngày sinh ']
var score = info['Điểm ']
data.push({
fullname,
code,
birthday,
classname: formatClassname(classname),
accademicTrainningList: {
score,
schoolYear,
semester,
classification:
(score >= 90 && 'Excellent') ||
(score >= 80 && score < 90 && 'Good') ||
(score >= 70 && score < 80 && 'Intermediate') ||
(score >= 60 && score < 70 && 'Average') ||
(score >= 50 && score < 60 && 'Weak') ||
(score < 50 && 'Fail')
}
})
})
})
req.data = data
next()
}
then in the next route, i insertMany into collection "students":
exports.add_students_from_excel = async (req, res, next) => {
const { data } = req
var studentList = []
data.forEach((student, index) => {
var {
fullname,
code,
birthday,
classname,
accademicTrainningList
} = student
studentList.push({
fullname,
birthday,
classname,
code,
vnumail: code + '#vnu.edu.vn',
classname,
accademicTrainningList
})
})
Student.insertMany(studentList, { ordered: false })
.then(docs => {
console.log('new students were inserted, reload the database')
next()
})
.catch(err => {
if (
(err.name === 'BulkWriteError' || err.name === 'MongoError') &&
err.code === 11000
) {
console.log('new students were inserted, reload the database')
next()
} else {
res.status(500).json({ err })
}
})
}
I succeeded and I added data about new class in model "class" and student list in model "student". This is the input data image and the result is saved on the mongo atlas
But as you can see, the "academicTrainningList" attribute in the "student" model is an array and I just added the first one, now I want to add more items for the second semester of 2016 and the next, i will have to updateMany, the input will be an xlsx file with the same student list and the score will be different, but i don't know what the syntax will look like, i'm a complete newbie and self-taught, thank you for your time time to read through this post and take the time to help me, it is very meaningful to me, have a nice day
If you want to update many resources you could .find(query) the resources and then for each resource:
forEach((doc)=>{doc.academicTrainingList.push(NEW_ITEM)}
I don´t know the logic behind your .xlsx files, but you could search your item Id in the table to find the correct NEW_ITEM to push to the array

How to save data in mongoDB and Schema is like bellow

Here is my schema by using mongoose npm package.
var StatusSchema = new mongoose.Schema({
empName: {
projectName: { type: String },
clientName: { type: String },
statusLastWeek: { type: String },
statusThisweek: { type: String },
planNextWeek: { type: String }
}
});
Here is my nodejs code to update the data
var Status = mongoose.model('Status', StatusSchema);
module.exports = Status;
Description: Want save data in MongoDB, data schema is like above mentioned,
save saving data is sored loke as bellow.
Inside Mongo DB :
{ "_id" : ObjectId("5d92f4aba4695e2dd90ab438"), "__v" : 0 }
{ "_id" : ObjectId("5d92f4b4a4695e2dd90ab439"), "__v" : 0 }
Expected collection in MongoDB :
Dave Smith {
projectName: BLE Mesh,
clientName: Tera,
statusLastWeek: BLE Scan,
statusThisweek: BLE List View,
planNextWeek: Mqtt config
}
Here you can see my NodeJS code :
router.post ('/update', (req,res,next)=>{
userStatus = new wkStatus(req.body)
userStatus.save()
.then(status => {
res.redirect('/success');
console.log ("Status saved in DB")
})
.catch(err => console.log(err))
// return next;
});
//You can use ODM like mongoose and define a schema with mongoose.Schema. You can just
// see mongoose module document from npm. Use .save() for save an object in DB.
// Example :
// schema as admin
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const Schema = mongoose.Schema;
const bcrypt = require('bcrypt-nodejs');
const sha256 = require('sha256')
const adminSchema = new Schema({
fullName: { type: String, required: true },
userName: { type: String },
noc: { type: String, required: true },
mobileNumber: { type: String, required: true },
email: { type: String },
chacommAddress: {
contactPerson: { type: String },
country: { type: String },
address: { type: String },
city: { type: String },
pinCode: { type: String },
state: { type: String },
stateCode: { type: String },
},
address: {
country: { type: String },
city: { type: String },
pinCode: { type: String },
state: { type: String },
stateCode: { type: String },
address: { type: String },
CIN: { type: String },
GSTIN: { type: String }
},
password: { type: String, required: true },
userType: { type: Number, required: true },
createdAt: { type: Date, required: true },
uploadFile: { type: String, required: true },
bankdetails: {
bankName: { type: String },
accountNo: { type: String },
ifscCode: { type: String },
accountType: { type: String },
accountName: { type: String },
cancelledChequeCopy: { type: String }
},
isActive: { type: Boolean },
invoiceString:{type:String},
invoiceValue:{type:Number},
accountantName :{type:String} ,
accountantDesignation : {type:String},
referredBy:{type:String}
});
adminSchema.methods.comparePassword = function (password) {
let password_hash = sha256(password);
return bcrypt.compareSync(password_hash, this.password);
}
adminSchema.pre('save', function (next) {
if (!this.isModified('password'))
return next();
let password_hash = sha256(this.password);
bcrypt.hash(password_hash, null, null, (err, hash) => {
if (err)
return next(err);
this.password = hash;
next();
});
});
//export schema
// module.exports = mongoose.model('Admin', adminSchema)
// for save:
const admin = require('admin')
var obj= new admin({
// values as per model defined
})
obj.save()
const wkStatus = new wkStatus({
_id: new mongoose.Types.ObjectId(),
projectName: req.body.projectName,
clientName: req.body.clientName,
statusThisweek: req.statusThisweek,
statusLastWeek: req.statusLastWeek,
planNextWeek: req.planNextWeek
})
Status
.save()
.then(result => {
res.status(201).json({
message: "Data Created Successfully",
})
console.log(result) // show the response
})
.catch(err => {
res.status(500).json({error:err})
})
Try this way hope it will work. If need more you can message me
The schema what you are trying to create itself is wrong.
empName: {
projectName: { type: String },
clientName: { type: String },
statusLastWeek: { type: String },
statusThisweek: { type: String },
planNextWeek: { type: String }
}
The above schema can create objects like below: "empName" cannot be dynamic.
empName: {
projectName: BLE Mesh,
clientName: Tera,
statusLastWeek: BLE Scan,
statusThisweek: BLE List View,
planNextWeek: Mqtt config
}
If you want to store like what you have shown, where empName dynamically then you should make empName as Map
See https://mongoosejs.com/docs/schematypes.html#maps

Express, Mongoose - .update() is returning null

When I am trying to update a document in my model, the .update() is returning null but the .find() method works fine.
module.exports.updateBio = function(req, res) {
var userID = req.params.id;
var objForUpdate = {};
if (!troolr.isEmptyString(req.body.profile_picture)) objForUpdate.profile_picture = req.body.profile_picture;
if (!troolr.isEmptyString(req.body.title)) objForUpdate.title = req.body.title;
if (!troolr.isEmptyString(req.body.intro)) objForUpdate.intro = req.body.intro;
if (!troolr.isEmptyString(req.body.summary)) objForUpdate.summary = req.body.summary;
if (!troolr.isEmptyString(req.body.skills)) objForUpdate.skills = req.body.skills;
if (!troolr.isEmptyString(req.body.facebook)) objForUpdate.social.facebook = req.body.facebook;
if (!troolr.isEmptyString(req.body.twitter)) objForUpdate.social.twitter = req.body.twitter;
if (!troolr.isEmptyString(req.body.linkedin)) objForUpdate.social.linkedin = req.body.linkedin;
if (!troolr.isEmptyString(req.body.website)) objForUpdate.social.website = req.body.website;
var conditions = { "_id": userID }
, setObj = { $set: objForUpdate }
, options = { multi: true };
//This throws error
// Error: { ok: 0, n: 0, nModified: 0 }
Profile.update(conditions, setObj, (err, page) =>{
if(err) throw err;
console.log(page);
});
// This works fine but it erases old values if they are empty
/* Profile.findById(userID, (error, user) => {
if(error) return res.status(500).json({ success: false, error: error });
user.bio = objForUpdate;
user.save(function(error) {
if(error) return res.status(500).json({ success: false, error: error });
return res.status(200).json({ success: true, message: "Bio successfully updated." });
});
}); */
};
// API Endpoint
http://localhost:3000/api/v1/profile/592c53b3bdf350ce004ad717/updatebio
// API Define
'use strict';
/**
* Routes for Profile Model
*
**/
var passport = require('passport');
var jwt = require('jwt-simple');
var settings = require("settings");
var profileCtrl = require(settings.PROJECT_DIR + 'routes/controllers/api/profile');
module.exports = function(app) {
app.get('/all', profileCtrl.getAll);
app.get('/:id', profileCtrl.getSingle);
app.put('/:id/updateurl', profileCtrl.updateURL);
app.put('/:id/updateaddress', profileCtrl.updateAddress);
app.put('/:id/updatebio', profileCtrl.updateBio);
}
// Model
var mongoose = require('mongoose');
// User Schema
var ProfileSchema = mongoose.Schema({
url : {
type: String,
unique: true,
},
fname: {
type: String,
required: true
},
lname: {
type: String,
required: true
},
email: {
type: String,
unique: true,
required: true
},
bio: {
profile_picture: {
type: String
},
title: {
type: String
},
intro: {
type: String
},
summary: {
type: String
},
skills: {
type: Object
},
social: {
linkedin: {
type: String
},
twitter: {
type: String
},
facebook: {
type: String
},
website: {
type: String
}
},
},
location: {
address: {
type: String
},
apt: {
type: String
},
city: {
type: String
},
state: {
type: String
},
zip_code: {
type: String
},
country: {
type: String
}
},
phone: {
type: Number
},
listings: {
type: Object
},
reviews: {
type: Object
},
verfied: {
type: Boolean,
default: false
},
// expires: {
// type: Date,
// expires: '1h',
// default: Date.now
// },
});
var Profile = module.exports = mongoose.model('Profile', ProfileSchema);
module.exports.getUserByEmail = function(email, callback){
var query = {'email': email};
Profile.findOne(query, callback);
}
module.exports.checkIfUrlExists = function(res, url, callback){
var query = {'url': url};
Profile.findOne(query, function(error, found) {
if(error) return res.status(500).json(error);
if(found) return res.status(500).json({success: false, message: "URL already exists" });
if(callback) callback();
});
}
// Document which I am trying to update
{
"_id": "592c53b3bdf350ce004ad717",
"url": "hyoh7ryb-",
"fname": "Foo",
"lname": "Bar",
"email": "foobar#gmail.com",
"__v": 0,
"verfied": false
}
Anything not defined in schema is not saved. That's what happening when you're missing bio key while preparing the objForUpdate to $set:
var objForUpdate = {};
if (!troolr.isEmptyString(req.body.profile_picture)) objForUpdate.profile_picture = req.body.profile_picture;
which should be
var objForUpdate = {
bio: {}
};
if (!troolr.isEmptyString(req.body.profile_picture)) objForUpdate.bio.profile_picture = req.body.profile_picture;
if (!troolr.isEmptyString(req.body.title)) objForUpdate.bio.title = req.body.title;
// and so on
Your save is working because of saving the object in the right keyuser.bio = objForUpdate;

Model.function is not a function within a router

Im currently stuck at a problem within my router.
I export the function as you see in the following code.
This is my Model:
"use strict";
var mongoose = require('mongoose');
var bcrypt = require("bcryptjs");
var Schema = mongoose.Schema;
var UserSchema = mongoose.Schema({
username: {
type: String,
index: true,
required: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
firstname: {
type: String,
required: true
},
lastname: {
type: String,
required: true
},
gender: {
type: String,
required: true
},
country: {
type: String,
required: true
},
confirm: {
type: Number
},
confirmcode: {
type: String
},
ip: {
type: String
},
signup: {
type: Date,
default : Date.now
},
voice: {
type: String
},
steam: {
type: String
},
steamid: {
type: String
},
steamlink: {
type: String
},
battletag: {
type: String
},
showsteam: {
type: Number
},
showbnet: {
type: Number
},
birthdate: {
type: Date,
required: true
},
language: {
type: String
}
});
var User = module.exports = mongoose.model('User',UserSchema);
module.exports.createUser = function(newUser, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash) {
newUser.password = hash;
newUser.save(callback);
});
});
}
module.exports.comparePw = function(canPw, hash, callback){
bcrypt.compare(canPw, hash).then((res) => {
callback(null,res);
});
}
module.exports.findUserById = function(id,callback){
User.findById(id,callback);
}
module.exports.getGamer = function(count,callback){
User.count(count,callback);
}
module.exports.findUsername = function(uname, callback){
var query = {username:uname};
User.findOne(query,callback);
}
module.exports.findEmail = function(email, callback){
var query = {email:email};
User.findOne(query,callback);
}
This is my Router:
var User = require("../../model/user");
module.exports = function(router){
router.get("/user", function(req, res){
var user = new User();
user.getGamer(function(err,response){
if(err){
throw err;
}else{
res.json(response);
}
});
});
}
the error i get is:
TypeError: user.getGamer is not a function
But i dont know why. Anyone can help me ?
You need to attach model methods to the schema, not to the model. Then the methods will be available on instances of your model. See this post for more.
UserSchema.methods.getGamer = function(newUser, callback) ...

Mongoose - when use populate no records otherwise array of records

I'm learning MeanJS and I have problem with Mongoose. I have two models:
var CategorySchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Category name',
trim: true
},
slug: {
type: String,
default: '',
trim: true,
unique: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
articles: [{
type: Schema.ObjectId,
ref: 'Article'
}]
});
var ArticleSchema = new Schema({
created: {
type: Date,
default: Date.now
},
category: {
type: Schema.ObjectId,
ref: 'Category'
},
title: {
type: String,
default: '',
trim: true,
required: 'Title cannot be blank'
},
slug: {
type: String,
default: '',
trim: true,
unique: true
},
content: {
type: String,
default: '',
trim: true
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
I'm saving articles like this:
exports.create = function(req, res) {
var article = new Article(req.body);
article.user = req.user;
article.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
Category.findById(article.category).exec(function(err, category) {
category.articles.push(article.category);
category.save(function(err, category) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(article);
}
});
});
}
});
};
and it's saving properly. The object looks like this:
{
"_id" : ObjectId("55b73bf97aa70c2c083655b0"),
"user" : ObjectId("55b115f35c7a03cc0e59d821"),
"articles" : [
ObjectId("55b73c017aa70c2c083655b2"),
ObjectId("55b73ee20bab5e8c0c7eadca")
],
"created" : ISODate("2015-07-28T08:23:21.562Z"),
"slug" : "motocycles",
"name" : "Motocycles",
"__v" : 2
}
and even when I'm counting records like {{ category.articles.length }} it's proper amount of articles in category and I can even print ObjectIds in the view. But when I add .populate('articles') like this:
exports.list = function(req, res) {
Category.find().sort('-created').populate('user', 'displayName').populate('articles').exec(function(err, categories) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(categories);
}
});
};
the length returns 0, ObjectIds disapears and I have no access to article properties just like there was no articles in category. Any ideas why is that happening?
Additional edit:
mongoose.model('Article', ArticleSchema);
mongoose.model('Category', CategorySchema);
It seems that the problem was with create function. I've changed few things and it started working:
exports.create = function(req, res) {
var article = new Article(req.body);
article.user = req.user;
article.save(function(err, savedArticle) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
Category.findById(article.category).exec(function (err, category) {
category.articles.push(savedArticle);
category.markModified('articles');
category.save(function (err, category) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(savedArticle);
}
});
});
}
});
};
I'm curious why it wasn't working even though Category object had proper Article ObjectId's.
First, some changes with regard to variables,schema instances and using ObjectId(The mongoose documentation isn't the best).
var categorySchema = new mongoose.Schema({
name: {
type: String,
required: 'Please fill Category name',
trim: true
},
slug: {
type: String,
trim: true,
unique: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: mongoose.Types.Schema.ObjectId,
ref: 'User'
},
articles: [{
type: mongoose.Types.Schema.ObjectId,
ref: 'Article'
}]
});
var articleSchema = new mongoose.Schema({
created: {
type: Date,
default: Date.now
},
category: {
type: mongoose.Types.Schema.ObjectId,
ref: 'Category'
},
title: {
type: String,
trim: true,
required: 'Title cannot be blank'
},
slug: {
type: String,
trim: true,
unique: true
},
content: {
type: String,
trim: true
},
user: {
type: mongoose.Types.Schema.ObjectId,
ref: 'User'
}
});
You need to export your models if you are using an MV* pattern with separate files for separate concerns. So...
exports.method = mongoose.model('Category',categorySchema);
exports.otherMethod = mongoose.model('Article',articleSchema);
. method and .otherMethod are from nodejs. Not sure about express equivalent or what express itself uses.
Then just name this file and require it using its path.

Categories