I have an mongoose schema with some properties and subproperties. On the version property I want a subproperty with the Mixed type, because I will send different key/value pairs to this property. But after sending the data to node, the subproperty is empty and is not saved in MongoDB.
This is my Schema
var Product = new mongoose.Schema({
name: {
type: String
},
nameSlug: {
type: String
},
uploader: {
_id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true
}
},
uploadDate: {
type: Date,
default: Date.now,
required: true
},
dateLastModified: {
type: Date,
default: Date.now,
},
isBestseller: {
type: Boolean,
default: false,
required: true
},
isVerified: {
type: Boolean,
default: false
},
suggestedRetailPrice: {
type: Number
},
brand: {
_id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true
},
nameSlug: {
type: String,
required: true
},
images: [Image]
},
productCollection: {
type: String
},
category: {
type: String,
required: true
},
versions: [{
author: [{
name: String,
_id: false
}],
date: {
type: Date,
required: true
},
concept: {
type: Boolean,
required: true
},
modifiedProperties: [mongoose.Schema.Types.Mixed],
history: [{
status: String,
author: [{
name: String,
_id: false
}],
date: Date
}]
}]
}, {strict: false});
module.exports = mongoose.model('Product', Product);
Image an subschema which is not relevant now. On the versions property I have an modifiedProperties property which I want to fill with the changed product (name, nameslug, etc) properties on a update in my Angular application. I create that object as follows
Angular code
var modifiedProperties = [];
angular.forEach($scope.addProductForm, function(value, key) {
if(key[0] == '$') return;
if(value.$dirty){
modifiedProperties[key] = value.$$lastCommittedViewValue;
}
});
var version = {
author: {
name: $rootScope.user.firstName + ($rootScope.user.lastNamePrefix ? " " + $rootScope.user.lastNamePrefix + " " : " ") + $rootScope.user.lastName,
_id: $rootScope.user._id
},
date: new Date(),
concept: true,
modifiedProperties: modifiedProperties,
history: {
author: {
name: $rootScope.user.firstName + ($rootScope.user.lastNamePrefix ? " " + $rootScope.user.lastNamePrefix + " " : " ") + $rootScope.user.lastName,
_id: $rootScope.user._id
},
status: "Versie aangemaakt",
date: new Date()
}
}
console.log("VERSION", version);
var product = $scope.product;
product.versions.push(version);
$api.update('products/' + nameSlug, product)
.then(function(response) {
console.log("response", response);
})
.catch(function(reason) {
console.log(reason);
})
In the console I see the properties correctly filled in, but after a save operation everything but modifiedProperties is saved. I placed some logs in the update function, and what I see is that the modifiedProperties is empty in the controller. I don't know where he lose it's data.
The $api service is our wrapper for the $http function. The data is there not loose, and will we be send using the data field.
The controller
module.exports.updateProduct = function(req, res) {
console.log('[updateProduct controller]');
/* This helper function can be called from elsewhere in the updateProduct controller and processes the HTTP response (and possibly errors) */
function sendResponse(status, response, err) {
/* Log HTTP response to the console server side before actually sending it to the client. */
console.log(status + ' ' + response.message);
/* Also log stack trace on error */
if(err) {
console.log('\nError message: ' + err);
console.log(err.stack);
}
/* Send HTTP response */
res.status(status).json(response);
}
if(req.params && req.params.nameSlug && req.body) {
//Empty modifiedProperties (Array(0))
console.log("REQ", req.body");
let verifyProduct;
if(req.body.verifyProduct && req.body.verifyProduct == true) {
verifyProduct = true;
delete req.body.verifyProduct;
}
console.log("PRODUCT", req.body);
req.body.dateLastModified = Date.now();
Product.findOneAndUpdate({nameSlug:req.params.nameSlug}, req.body, function (err, product) {
/* Some error occurred while trying to update the product. */
if(err) {
sendResponse(400, {message: 'Product could not be added. '}, err);
/* The product doesn't exist */
} else if(!product) {
sendResponse(404, {message: 'Product not found. '});
/* The product exists and has been updated successfully. */
} else {
/* Check if this product is being verified by an admin or not. If so, check if the admin is the same person who initially uploaded the product. */
if(verifyProduct == true && product.uploader._id != req.user._id) {
/* If so, find that user to get their email adress. */
User.findById(product.uploader._id, function(err, user) {
/* An error occurred, so mailing the original uploader is not possible. */
if(err) {
sendResponse(200, {message: 'Product updated with errors. ', product}, err);
/* The original uploader does not exist (anymore), so sending mail is not possible. */
} else if(!user) {
sendResponse(200, {message: 'Product updated, but the uploader doesn`t seem to exist. ', product});
/* Send an email to the original uploader to notify them. */
} else {
var data = {
product: product,
user: user
};
var options = {
to: user.email,
subject: product.en.name + ' is toegevoegd aan PrismaNote!',
template: 'retailer-product-verified'
};
mailService.mail(options, data, null);
sendResponse(200, {message: 'Product updated. ', product});
}
});
} else {
sendResponse(200, {message: 'Product updated. ', product});
}
}
});
}
};
Does anybody know where this can go wrong? Or why this is happen?
Edit:
I see the array modifiedProperties has a length of '0' because of the keys. Is that maybe the reason why nodejs won't proces it?
Hmm, I doesn't still know what is going wrong, but I have solved it, with passing the modifiedProperties directly to product and not in product.versions.
So, my req.body now looks like
name: "testproduct",
nameSlug: "testproduct",
isBestseller: false,
[other properties]
modifiedProperties: {
testfield: "testvalue",
field2: "value2"
},
versions: {
[
date: [today],
concept: true,
[other properties]
],
[
date: [today],
concept: true,
[other properties]
],
}
Related
I have a collection of online users here goes its model
var SessionDetailSchema = mongoose.Schema({
providerID: {
type: String
},
firstName: {
type: String
},
email: {
type: String
},
status: {
type: String
}
},{ timestamps: true });
var sessionDetail = module.exports = mongoose.model('OnlineUser', SessionDetailSchema);
I am trying to send an array of providerID's so that I wanted to check the collection which all providerId's are present and return me those providerID details.
and this is what I tried
router.post('/sessiondetails:find', function (req, res, next) {
console.log(req.body.providerID)
sessionDetail.find({ "providerID": { $in: req.body.providerID} }, function (err, users) {
if (users) {
console.log(users)
} else {
console.log("not there")
}
})
})
unfortunately, I am getting the only first providerid response for multiple times.
i am sending the array from the postman it looks like this
{
"providerID":["1090867867720278", "104761648907225164100", "114316680403119099502", "103668441331122956874"]
}
can some help me? thanks in advance.
I would really like some help with this problem, I am sorta stuck. I am trying to manipulate this UserSchema. I want to be able to edit and delete the shippings array within the model but I am having trouble trying to figure out how to access individual items in the array to use an express restAPI. Below is a snippet of the schema and the restAPI endpoint for creating multiple shipping addresses I was able to write. The create endpoint is working but for some reason I am unable to wrap my head around updating and deleting. Any help would be appreciated.
Thanks
var UserSchema = new Schema({
firstname: {
type: String,
default: ''
},
lastname: {
type: String,
default: ''
},
email: {
type: String,
unique: true,
lowercase: true,
},
password: {
type: String,
},
shippings: [{
recipient: {
type: String,
default: ''
},
street: {
type: String,
default: ''
},
city: {
type: String,
default: ''
},
state: {
type: String,
default: ''
},
zip: {
type: String,
default: ''
}
}],
exports.postShipping = function(req, res, next) {
req.assert('recipient', 'Recipient cannot be blank').notEmpty();
req.assert('street', 'Street Address cannot be blank').notEmpty();
req.assert('city', 'City cannot be blank').notEmpty();
req.assert('state', 'State cannot be blank').notEmpty();
req.assert('zip', 'Zip Code cannot be blank').notEmpty();
// req.assert('country', 'Country cannot be blank').notEmpty();
User.findById(req.user.id, function(err, user) {
if (err) return next(err);
var shipping = {};
shipping.street = req.body.street;
shipping.recipient = req.body.recipient;
// shipping.unit = req.body.unit;
shipping.city = req.body.city;
shipping.state = req.body.state;
shipping.zip = req.body.zip;
// shipping.country = req.body.country;
var s = JSON.stringify(shipping);
console.log(s);
var duplicatedShipping = 0;
for (var i in user.shippings) {
console.log(JSON.stringify(user.shippings[i]));
if (JSON.stringify(user.shippings[i]) == s) {
duplicatedShipping = 1;
break;
}
}
if (duplicatedShipping === 0) {
user.shippings.push(shipping);
}
user.save(function(err) {
if (err) return next(err);
console.log(user.shippings);
req.flash('success', {
msg: 'Shipping Address Added'
});
res.redirect('/account/me/shipping');
});
});
I would like to ask if there is anyone getting the same response on JSON format:
Objectdata: "User is not authorized"headers: (name) {status: 403statusText: "Forbidden"
Scenario:
User A post a product and add comment on the product.
Result: Successful.
User B comment on the same product:
Result: User is not authorized.
The code I'm using to update the product comment is here:
applicationname/`
// Add comment to Product
$scope.comment = function(){
// console.log("name: ",$scope.user);
// console.log("textarea: ",this.commentarea);
var comment = {
name: $scope.product.user.displayName,
text: this.commentarea
};
$scope.product.comments.push(comment);
$scope.product.$update(function() {
console.log('success update');
}, function(errorResponse) {
console.log('success error', errorResponse);
});
};
This is the server side.
'use strict';
/**
* Module dependencies.
*/
var init = require('./config/init')(),
config = require('./config/config'),
mongoose = require('mongoose'),
chalk = require('chalk');
/**
* Main application entry file.
* Please note that the order of loading is important.
*/
// Bootstrap db connection
var db = mongoose.connect(config.db, function(err) {
if (err) {
console.error(chalk.red('Could not connect to MongoDB!'));
console.log(chalk.red(err));
}
});
// Init the express application
var app = require('./config/express')(db);
// Bootstrap passport config
require('./config/passport')();
// Start the app by listening on <port>
app.listen(config.port);
// Expose app
exports = module.exports = app;
// Logging initialization
console.log('MEAN.JS application started on port ' + config.port);
If your Products schema looks like this:
var ProductSchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true,
required: 'Title cannot be blank'
},
comments: [{
type: String,
default: '',
trim: true
}]
});
And you have restricted your products route in your app/routes/products.server.routes.js file like so:
app.route('/products/:productId')
.get(products.read)
.put(users.requiresLogin, products.hasAuthorization, products.update)
.delete(users.requiresLogin, products.hasAuthorization, products.delete);
Then a non-authorized user cannot add a comment because they can't update the Product record.
You probably want to create a separate CommentsSchema and use the Mongoose ObjectId type to create a one-to-many relationship with the product:
var CommentSchema = new Schema({
product: ObjectId,
content: {
type: String,
default: '',
trim: true,
required: 'Content cannot be blank'
},
})
That will preserve the security of your product and allow non-authorized users to comment, but would require you to do slightly more complex queries to get your comments in your product view.
This is working code to populate my Locations collection, which can have self-referencing child Locations. It uses mongoose-deep-populate. But I need to add another ".childLocations" to my path variable for every extra level of depth that I want to handle. Is there a better way to accomplish unknown depths of self-references?
I have this node.js code.
var path = 'childLocations.childLocations.childLocations.childLocations.childLocations.childLocations';
exports.list = function(req, res) {
Location.find().sort('-created').populate('user', 'displayName').deepPopulate(path).exec(function(err, locations) {
console.log(locations);
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(locations);
}
});
};
Here is the schema:
var LocationSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Location name',
trim: true
},
projectsExecutedHere: Boolean,
childLocations: [{
type: Schema.ObjectId,
ref: 'Location'
}],
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Location', LocationSchema);
var deepPopulate = require('mongoose-deep-populate');
LocationSchema.plugin(deepPopulate);
----------
Before trying mongoose-deep-populate, I had seen that mongoose 3.6 had support for deep population, but I could only make it go one level deep. This is what I tried:
Location.find().sort('-created').populate('user', 'displayName').populate('childLocations').exec(function (err, locations) {
Location.populate(locations, {path: 'childLocations.childLocations'},
function (err, data) {
console.log(err);
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(locations);
}
}
);
For the path I also tried 'childLocations.childLocations.childLocations' but it didn't populate it at all.
I'm trying to create a small prediction game for football world cup with MEAN stack, but I have a problem that I need to get all the predicted games of user and all that are not predicted yet separately.
My schemas are (users schema is the default mean-stack):
/**
* Prediction Schema
*/
var PredictionSchema = new Schema({
game_id: {
type: Schema.ObjectId,
ref: 'Game'
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
date: {
type: Date,
default: Date.now
},
choice: {
type: Number
}
});
And game schema:
var GameSchema = new Schema({
team1_key: {
type: String
},
team1_title: {
type: String
},
team2_key: {
type: String
},
team2_title: {
type: String
},
play_at: {
type: Date
},
score1: {
type: Number
},
score2: {
type: Number
}
});
mongoose.model('Game', GameSchema);
Anyway, what I'm trying to achieve is to get all games that are mentioned in all predictions and with the active user.
I tried like this, but it does not work:
/**
* List of Games predicted
*/
exports.allPredicted = function(req, res) {
Game.find({_id: {$in: Prediction.distinct('game_id')}}).sort('-created').populate('user', 'name username').exec(function(err, games) {
if (err) {
res.render('error', {
status: 500
});
} else {
res.jsonp(games);
}
});
};
What's wrong? I got error:
Error: Failed to lookup view "error" in views directory "/Users/username/Projects/ProjectName/server/views"
Any ideas? Thanks! :)
EDIT:
Got distinct values, not sure if this the create way of doing it, but anyway works.. almost:
exports.allPredicted = function(req, res) {
Prediction.distinct('game_id').populate('user', 'name username').exec(function(err, predictions) {
if (err) {
res.render('error', {
status: 500
});
} else {
console.log(predictions);
Game.find({_id: {$in: predictions }}).sort('-created').populate('user', 'name username').exec(function(err, games) {
if (err) {
res.render('error', {
status: 500
});
} else {
res.jsonp(games);
}
});
}
});
};
Now I need, that it should consider the active user as well. Any help?
you can find your active user in
req.user
so try
Prediction.find({user : req.user._id}).sort('-created').populate('game_id').exec(function(err, predictions) {
if (err) {
res.render('error', {
status: 500
});
} else {
res.jsonp(predictions);
}
});
This should return all the predictions made by your user and replace the game_id by the game associated.
ps: I don't test it but i think this is the logic of request you're looking for.
ps2 : see http://mongoosejs.com/docs/populate.html if you want to populate your users data too