Mongoose subdocument not created in mongoDB but added to parent array - node.js

I have a method to update the commerce information. There is the possibility to add Workdays to the commerce by sending them in the request body.
There following code works fine except that the workdays are not created in mongoDB. They are only saved in the Commerce document (as an array od ids) but the Collection called "workday" is not createdin mongoDB. Why it's not created?
if(req.body.workdays){
var workdays = req.body.workdays;
var lunch = req.body.lunch.split("_");
commerce.workdays=[];
for(var i =0, size=workdays.length; i<size; i++ ){
var item=new Workday();
item.dayOfWeek = workdays[i];
item.owner=commerce._id;
var range = new Range();
range.initial = lunch[0];
range.end = lunch[1];
range.workday = item;
item.ranges.push(range);
commerce.workdays.push(item);
}
}
commerce.save(function(err) {
if(!err) {
log.debug('Updated');
res.status(200).send(commerce);
} else {
errorHandler.processError(err, res, log);
}
});
here are the models:
var CommerceSchema = new Schema({
// Common fields.
createdAt : {type : Date, default : Date.now},
location: [Number, Number],
photos: [{type : Schema.Types.ObjectId, ref : 'Photo'}],
name: { type: String},
address: { type: String},
email: { type: String, default: "-"},
workdays: [{type : Schema.Types.ObjectId, ref : 'Workday'}],
description: { type: String, default: "-"},
phone: { type: Number},
user: {type : String, ref : 'User'},
type: [{ type: Number, default: 0}]
});
var WorkdaySchema = new Schema({
dayOfWeek: { type: Number},
owner: {type : String},
ranges: [{type : Schema.Types.ObjectId, ref : 'Range'}],
createdAt : {type : Date, default : Date.now}
});
var RangeSchema = new Schema({
initial: { type: Number},
end: { type: Number},
workday: {type : String, ref : 'Workday'}
});

"workdays" is expecting Mongo ObjectIds. You have to save the individual Workdays first, and then you can add their Ids (_id) to the workdays Array.

Related

type Object Validation in Mongoose?

I am trying to do schema validation in mongoose of type object and array, but I am not able to do that. Here is the schema:
var alertEmailSchema = new alertEmailSchema({
templateId: { type: String, required: true,unique: true},
templateName : { type: String, required: true},
status: Boolean,
frequency : { type: Object, required: true},
recipientsEmailId : { type: [String], default: [], required: true},
subject : { type: String, required: true},
message : { type: String, required: true},
description : String,
createdDate : {type : Date, default : Date.now},
updatedDate : {type : Date, default : Date.now}
});
var schemaValidation = newAlertEmail.validateSync();
Please tell me how can I do the validation for this.
I assume you want something like this:
var frequency = new Schema({
count: {
type: Number
},
updateAt: {
type: Date
}
}, {
_id: false // this will not create _id for this schema
});
var alertEmailSchema = new Schema({
templateId: { type: String, required: true,unique: true},
templateName : { type: String, required: true},
status: Boolean,
frequency : frequency, //this can be an array also [frequency]
recipientsEmailId : { type: [String], default: [], required: true},
subject : { type: String, required: true},
message : { type: String, required: true},
description : String,
createdDate : {type : Date, default : Date.now},
updatedDate : {type : Date, default : Date.now}
});
Here, I created another schema known as frequency and used it in schema alertEmailSchema.

how can I rewrite my mongoose query after splitting data from one model into two?

In my application I store comments. Previously my model for that looked like this:
var CommentsSchema = new Schema({
username: {type: String},
display_name: {type: String},
facebook_username: {type: String},
text_content: {type: String},
photo_content_url: {type: String},
hashtags: {type: [String]},
device_id: {type: String},
comment_date: {type: Date, default: Date.now},
friends_only: {type: Boolean, default: false}
}
Each comment - besides storing its details - had also details about the author, e.g. username, facebook_username, device_id from which the comment was added and display_name. There was also a bool flag friends_only based on which I was deciding whether that comment should be visible only to user's facebook friends or to everyone.
Construction of the node.js/mongoose query for fetching all comments looked like this:
commentsRoutes.post('/friends', function (req, res) {
var friends = req.body.friends;
var publicComments = req.body.publicComments;
var hashtagsInput = req.body.hashtags;
var startDate = req.body.startDate;
var endDate = req.body.endDate;
var query= {};
query.$and = [];
// and condition on start date
if(startDate != undefined) {
var startDate = new Date(req.param('startDate'));
var endDate = new Date(req.param('endDate'));
query.$and.push({"comment_date":{$gte: startDate}});
query.$and.push({"comment_date":{$lte: endDate}});
}
// and condition on hastags
if (hashtagsInput != undefined) {
var hashtags = hashtagsInput.split(",");
query.$and.push({"hashtags":{$in: hashtags}});
}
// creating a OR condition for facebook friends and public flag
var friend_query = {};
friend_query.$or = [];
if (friends != undefined) {
var friendsSplit = friends.split(",");
friend_query.$or.push({"facebook_username":{$in: friendsSplit}});
}
if (publicComments != undefined && publicComments === "true") {
friend_query.$or.push({friends_only: false});
}
//Merging facebook friend condition with other condition with AND operator.
query.$and.push(friend_query);
var finalQuery = Comment.find(query)
With the code above user could fetch content posted by his friends (that was set either to public or private) and all other public content (from everyone else).
I've decided to change all of that and split the data into two models. After changing it I have:
var CommentsSchema = new Schema({
user_id: {type: String, required: true, ref: 'users' },
text_content: {type: String},
photo_content_url: {type: String},
hashtags: {type: [String]},
comment_date: {type: Date, default: Date.now},
friends_only: {type: Boolean, default: false},
device_id: {type: String}
}
and
var UsersSchema = new Schema({
username: {type: String},
facebook_username: {type: String},
display_name: {type: String}
}
Now, when I want to keep the old functionality, I need to modify the code responsible for creating the query.
I could merge two queries with async, or the other way is to use mongoose .populate option. I decided to go with the second choice, so now I need to move the code responsible for creating or query to the match part of populate function:
...
var finalQuery = Comment.find(query)
finalQuery.populate({path: 'user_id',
select: 'facebook_username display_name username',
match: {
}});
I don't know how to do it. Can you help me with that?
First, i suggest you that go with a populate query, if you feel that populate won't give you a data that you need that you can run two queries and merge those results.
for populate, i found the solution from the official doc of mongoose. you can do like this.
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
Story
.findOne({ title: 'Once upon a timex.' })
.populate('_creator')
.exec(function (err, story) {
if (err) return handleError(err);
console.log('The creator is %s', story._creator.name);
// prints "The creator is Aaron"
});
here is doc link: http://mongoosejs.com/docs/populate.html

Mongoose Populate Method is not populating value

I have two mongoose schema as following
var ServiceSubType = new Schema({
displaySubTypeName : String,
subTypeDescription : String,
status : { type: String, default: Constants.ACTIVE },
lastUpdatedOn : Date,
createdOn : { type: Date, default: Date.now }
} , { collection: 'SERVICE_SUB_TYPES' });
and
var ServiceType = new Schema({
displayName : String,
description : String,
status : { type: String, default: Constants.ACTIVE },
lastUpdatedOn : Date,
serviceSubTypeId : {type: Schema.Types.ObjectId, ref: 'ServiceSubType', index: true},
createdBy : { type: Schema.Types.ObjectId, ref: 'SystemUser', index: true },
createdOn : { type: Date, default: Date.now }
} , { collection: 'SERVICE_TYPES' });
I have populated Type Object as below
module.exports.addNewServiceType = function(serviceType_obj, callback) {
serviceType_obj.save(serviceType_obj,callback);
}
Now I am trying to populate ServiceSubType document and then at the same time trying to populate "serviceSubTypeId" of ServiceType object referenced to ServiceSubType created.
Here is my piece of code for the same purpose.
module.exports.addServiceSubType = function(serviceTypeObjId, serviceSubType_obj, callback) {
serviceSubType_obj.save(serviceSubType_obj, function (error, serviceSubType) {
});
serviceSchema.ServiceType.findById(serviceTypeObjId, function (err, serviceType) {
var opts = { path: 'serviceSubTypeId'};
serviceSchema.ServiceType.populate(serviceType, opts, function (err, user) {
console.log(serviceType);
});
}).exec(callback);
}
But it is not workign and not populating any value in Existing SubType object.
I admit my approach could be very wrong as I am very new in this technology. Appreciate any kind of help to run this piece of code as expected.
Thanks
Ajoy
I think your ref should be the same setting as the collection on the object
serviceSubTypeId : {
type: Schema.Types.ObjectId,
ref: 'SERVICE_SUB_TYPES', <==== your collection type goes here
index: true
},
Mongoose doesn't know anything about your JavaScript object types. Instead, it tracks things based on the collection name that you provide (or that it generates).
update based on comments below
I have some example code that I wrote a while back, and it looks like I'm letting Mongoose generate the collection name for me. However, I am supplying a name to the mogoose.model() call, when registering my type for a collection.
For example, I have a Post type and a User type. The Post contains an author which is a reference to the User.
It looks like this:
// post
// ----
var PostSchema = new mongoose.Schema({
date: {type: Date, required: true, default: Date.now},
title: {type: String, required: true},
content: {type: String, required: true},
author: {
type: SchemaTypes.ObjectId,
ref: "user"
},
comments: [CommentSchema]
});
var Post = mongoose.model("blog", PostSchema);
// user
// ----
var UserSchema = mongoose.Schema({
firstName: {type: String},
lastName: {type: String},
username: {type: String, required: true, index: {unique: true}},
email: {type: String, required: true},
password: {type: String, required: true},
url: {
type: mongoose.Schema.Types.ObjectId,
ref: "url"
}
});
User = mongoose.model("user", UserSchema);
In this example code, I'm setting the ref to "user" because I am registering my model as "user" down below, in the mongoose.model method call.
Are you registering your models using mongoose.model and supplying a name? if so, use that name.

Node.js - Create Relationships with Mongoose from different file

I have two Schemas Products and Users in different files. Products are belong to User and User have many Product
The Problem is, I have try to use Populate but somehow it return not what I expected.
here is my Schema for Product on models products.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var users = require('../models/users');
var Product = mongoose.Schema({
user_id : {type: String, required: true },
category_id : {type: String, default: null},
title : {type: String, required: true },
content : {type: String, default : "" },
pictureUrls : Array,
counter : {type : Number, default : 0},,
lowercaseTitle : {type: String, default : null },
_user : { type: Schema.Types.ObjectId, ref: users.User }
});
Product.set('toObject', {
getters: true,
virtuals: true
});
module.exports = mongoose.model('Product', Product)
and this is my Schema for User on models users.js
var mongoose = require('mongoose');
var User = mongoose.Schema({
firstName : {type: String, default: "" },
lastName : {type: String, default: "" },
username : {type: String, required: true },
email : {type: String, required: true },
password : {type: String, default: "" },
bio : {type: String, default: "" },
website : {type: String, default: "" },
phone : {type: String, default: "" },
gender : {type: String, default: "" },
birthDate : {type: Date, default: null },
avatarUrl : {type: String, default: "" },
verified : {type : Boolean, default : false}
});
User.set('toObject', {
getters: true,
virtuals: true
});
module.exports = mongoose.model('User', User);
currently I am using method find by calling each Models
User.findOne({"sessionToken" : bearerHeader}, function (err, user){
Product.find({"user_id" : user._id}, function (err, products){
console.log(products);
});
});
but it takes time and became problem if there related to another models.
I'm calling populte with this
Product.findOne({}).populate('_user').exec(function(err, p){
console.log(p);
});
but attribute _user was not set and undefined
any help?
Thanks

Mongoose Sorting

I have a problem with displaying data with sorting. Here is my query,
Activity.find({"user_id": sesUser._id}, {}, {offset: 0, limit : 5, sort:{createdAt:1}}, function (e,a){
...
});
I have data about 252 length, and my latest data is 9 June 2015. If i use this query i only get data from 5 June 2015/ last week data and not get the latest data, but if i not using sorting, the latest data is appear.
I have used this query below but turns out the result is same.
Activity.find({"user_id" : sesUser._id}).sort("createdAt").exec(function(err,a){
...
});
Any help? I'm using Mongoose v3
-- edited --
This is my Activity Schema / Model
var mongoose = require('mongoose');
var Activity = mongoose.Schema({
sender_id : {type: String, required: true },
user_id : {type: String, required: true },
product_id : {type: String, default : "" },
type : {type: String, required: true },
createdAt : {type: String, default : new Date()}
});
module.exports = mongoose.model('Activity', Activity);
`createdAt : {type: Date, default : new Date()}`
Type Date not string man
It will automatically create the createdAt and updatedAt
var options={
timestamps: true
}
var Activity = mongoose.Schema({
sender_id : {type: String, required: true },
user_id : {type: String, required: true },
product_id : {type: String, default : "" },
type : {type: String, required: true }
},options);

Resources