Document is not being saved in database - mongodb

In Article model, I want to save a list of categories:
var CategorySchema = new Schema({
name: String,
active: Boolean
});
var ArticleSchema = new Schema({
title: String,
description: String,
categories: [{ type : Schema.Types.ObjectId, ref: 'Category' }]
})
From the endpoint, I want to update article with categories. The update method looks like:
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
Article.findById(req.params.id, function (err, article) {
if (err) { return handleError(res, err); }
if(!article) { return res.send(404); }
var updated = _.merge(article, req.body);
updated.save(function (err, doc) {
console.log(doc);
if (err) { return handleError(res, err); }
return res.json(200, article);
});
});
};
Notice the console.log statement. In request.body, if I'm sending list of category ids, the console prints out an article with categories. However, when I look into the database, the category array is empty. Any pointer to how to solve this?

Related

unable to populate documents using mongoose populate()

I am making an application in express using mongoose. I have a collection called users in which there is a filed called _subscriptions, which is an array of objects and each object contains a field named field which is an ObjectId for the documents of fields (this is another collection in my db).
I want to make such an API which after getting id parameter returns me a user form users collection with field attribute populated instead of its id in value of the field field. For this I am using populate method but it is not working.
This is screenshot showing users collection:
This is screenshot showing fields collection:
This is schema for field (File name Field.js):
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var FieldSchema = new Schema(
{
_id: Schema.Types.ObjectId,
name: String,
price: Number,
_categories: [{
type: Schema.ObjectId,
}],
}
);
module.exports = mongoose.model('Field', FieldSchema);`
This is schema and model for users
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
_id: Schema.Types.ObjectId,
salt: String,
provider: String,
name: String,
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
_subscriptions: [{
field: {
type: mongoose.Schema.ObjectId,
ref: 'Field',
},
status: String,
dateSubscribed: Date,
payments: [{}]
}],
role: String,
});
module.exports = mongoose.model('User', UserSchema);
This is code for user router
var Field = require('../model/Field');
var express = require('express');
var router = express.Router();
var User = require('../model/User');
router.get('/',function(req, res, next) {
User.find({}, function(err, result) {
if (err) {
console.log(err);
res.send('something wrong');
}
res.status(200).send(result);
}).populate( '_subscriptions.field').exec(function (err, story) {
if (err) return handleError(err);
console.log('Here!!!!!');
});
});
router.get('/findById/:id',function(req, res, next) {
var id = req.params.id;
User.findById(id, function(err, doc) {
if (err) {
console.error('error, no entry found');
}
res.status(200).send(doc);
}).populate('field').exec(function (err, story) {
if (err) return handleError(err);
console.log('Here!!!!!');
});
});
router.get('/getSubscriptions/:id',function(req, res, next) {
var id = req.params.id;
User.findById(id, function(err, doc) {
if (err) {
console.error('error, no entry found');
}
var type = typeof(doc);
res.status(200).send(doc);
})
});
module.exports = router;
This is where I have called app.use method:
And this is response I am getting using postman
I am looking forward for someones' assistance in resolving this issue
as i am unable to identify my mistake. Your help in this regard will be highly appreciated.
Thanking in advance
What I have understood is, In the user collection, there is _subscriptions and in _subscriptions, there is field. If this is your schema, then you should pass "_subscriptions.field" as a parameter to the populate function not "field" as you have passed currently.
So, your code for user's sub route, /findById/:id, must be like this:
router.get('/findById/:id',function(req, res, next) {
var id = req.params.id;
User.findById(id, function(err, doc) {
if (err) {
console.error('error, no entry found');
}
res.status(200).send(doc);
}).populate('_subscriptions.field').exec(function (err, story) {
if (err) return handleError(err);
console.log('Here!!!!!');
});
});

moment js not updating in mongoose

So I am having trouble with momentjs. The timestamp is not updating when I make a post call. I waited for 30 seconds to make another post call and I still get the same time. How can I fix this? Below is my code so let me know what I am doing wrong.
var mongoose = require('mongoose');
var moment = require('moment');
var now = moment();
var UserSchema = new mongoose.Schema({
email: { type: String, default: ''},
name: { type: String, default: ''},
password: { type: String, default: ''},
timestamp: {type: String, default: now.format("dddd, MMMM Do YYYY, h:mm:ss a")}
});
module.exports = mongoose.model('UserSchema', UserSchema);
module.exports = {
find: function(params, callback) {
User.find(params, function(err, result) {
if (err) {
callback(err, null);
return;
}
callback(null, result);
return;
});
},
create: function(params, callback) {
User.create(params, function(err, result) {
if (err) {
callback(err, null);
return;
}
callback(null, result);
return;
});
}
}
router.post('/', function(req, res, next) {
UserController.create(req.body, function(err, result) {
if (err) {
res.json({
confirmation: 'fail',
message: err
});
return;
}
res.json({
confirmation: 'success',
result: result
});
return;
});
return;
});
This line of code will only be executed once, when the module is loaded:
var now = moment();
So the same value of now will be used for all documents.
Instead, your schema definition should use a function which will be called each time a new document is created:
var UserSchema = new mongoose.Schema({
email: { type: String, default: ''},
name: { type: String, default: ''},
password: { type: String, default: ''},
timestamp: {
type: String,
default: () => moment().format("dddd, MMMM Do YYYY, h:mm:ss a")
}
});
As a side note, consider using a Date data type instead of string for your timestamp as it's more flexible and efficient.

Finding ID using MongoDB .find()

I am trying to loop through something but first I need to do a mongo query to get the data for the loop my query is this:
AP.find({}, function(err, allAP) {
var ID = req.user.id;
if(err){
console.log(err);
} else {
res.locals.aps= allAP; // Set the data in locals
next();
}
});
I know I need to add something in the {} part on line 1. How do I take req.user.id and then only find documents with the author.id (see below)
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
email: String
}
Example document currently returned:
{ _id: 59e517230a892a26cb1b7635,
manufacturer: 'other',
model: 'Test Model',
bands: '2.4',
channel: 11,
notes: 'I am a test note for the first access point',
__v: 0,
author: { id: 59d7f98a77fcc221d6e3c93d, email: 'joe#example.com' } },
You can do
AP.find({"author.id":req.user.id}, function(err, allAP) {
if(err){
console.log(err);
} else {
res.locals.aps= allAP; // Set the data in locals
next();
}
});

How to make querys when tou have many to many relationships between models?

i am trying to make a game. I need tu create a Match. I think the problem on this Way. The User create a Match. In a third table I save playerId and gameId. When another user join the match, I save again, playerId and gameId. Then, I make a query with player with gameId in common, and start the game.
first, One User may have many Games. second, One Match may have many Games. this is the Match model:
module.exports = {
attributes: {
name: {
type: 'string'
},
description: {
type: 'string'
},
game: {
collection: 'game',
via: 'gameId',
}
}
};
This is the User model:
var bcrypt = require('bcrypt');
module.exports = {
attributes: {
name: {
type:'string'
},
email: {
type: 'email',
required: true,
unique: true
},
password: {
type: 'string',
},
passwordConfirmation: {
type: 'string'
},
passwordEncrypted: {
type: 'string'
},
creator: {
collection: 'game',
via: 'playerId'
},
toJSON: function(){
var obj = this.toObject();
delete obj.password;
delete obj.passwordConfirmation;
delete obj._csrf;
return obj;
}
}, beforeCreate: function(values, next){
console.log("Acabo de entrar a eforeCreate");
var password = values.password;
var passwordConfirmation = values.passwordConfirmation;
if(!password || !passwordConfirmation || password != values.passwordConfirmation) {
var passwordDoesNotMatchError = [{
name: 'passwordDoesNotMatchError',
message: 'Las contraseñas deben coincidir'
}]
return next({
err: passwordDoesNotMatchError
});
}
require('bcrypt').hash(values.password, 10, function passwordEncrypted(err, EncryptedPassword){
values.EncryptedPassword = EncryptedPassword;
next();
});
}
};
This is the Game model:
module.exports = {
attributes: {
gameId: {
model: 'match'
},
playerId: {
model: 'user'
}
}
};
finally, this is my controller:
module.exports = {
createMatch: function(req,res){
var matchObj = {
name: req.param('name'),
description: req.param('description'),
}
Match.create(matchObj, function(err, match){
if(err){
console.log("el error fue: " + err);
return res.send(err);
} console.log("Entro en create");
return res.json(match);
})
var gameObj = {
gameId: 'aclaration: I dont know how do I get the match.id',
playerId: req.session.me
}
Game.create(gameObj,function(err,game){
console.log("entro a GameCreate");
if(err){
return res.send(err);
} return res.json(game);
})
}
};
I can create the Match, but Game.create send this error:
_http_outgoing.js:344 throw new Error('Can\'t set headers after they are sent.'); ^
Error: Can't set headers after they are sent.
Somebody can help me? probably, I have many errors. Thanks.
Couple of things here:
Having an explicit Game model is not required in Sails. It can manage it implicitly, unless you want to store more information than just gameId and userId. So, you can just do away with Game model.
Please refer for async programming: How do I return the response from an asynchronous call?
Below code should work for you. Hope it helps.
module.exports = {
createMatch: function(req, res) {
var matchObj = {
name: req.param('name'),
description: req.param('description'),
};
Match.create(matchObj, function(err, match) {
if (err) {
console.log("el error fue: " + err);
return res.send(err);
}
console.log("Entro en create");
var gameObj = {
gameId: match.id,
playerId: req.session.me
};
Game.create(gameObj, function(err, game) {
console.log("entro a GameCreate");
if (err) {
return res.send(err);
}
return res.json(game);
// return res.json(match);
});
});
}
};

How to update embedded document in mongoose?

I've looked through the mongoose API, and many questions on SO and on the google group, and still can't figure out updating embedded documents.
I'm trying to update this particular userListings object with the contents of args.
for (var i = 0; i < req.user.userListings.length; i++) {
if (req.user.userListings[i].listingId == req.params.listingId) {
User.update({
_id: req.user._id,
'userListings._id': req.user.userListings[i]._id
}, {
'userListings.isRead': args.isRead,
'userListings.isFavorite': args.isFavorite,
'userListings.isArchived': args.isArchived
}, function(err, user) {
res.send(user);
});
}
}
Here are the schemas:
var userListingSchema = new mongoose.Schema({
listingId: ObjectId,
isRead: {
type: Boolean,
default: true
},
isFavorite: {
type: Boolean,
default: false
},
isArchived: {
type: Boolean,
default: false
}
});
var userSchema = new mongoose.Schema({
userListings: [userListingSchema]
});
This find also doesn't work, which is probably the first issue:
User.find({
'_id': req.user._id,
'userListings._id': req.user.userListings[i]._id
}, function(err, user) {
console.log(err ? err : user);
});
which returns:
{ stack: [Getter/Setter],
arguments: [ 'path', undefined ],
type: 'non_object_property_call',
message: [Getter/Setter] }
That should be the equivalent of this mongo client call:
db.users.find({'userListings._id': ObjectId("4e44850101fde3a3f3000002"), _id: ObjectId("4e4483912bb87f8ef2000212")})
Running:
mongoose v1.8.1
mongoose-auth v0.0.11
node v0.4.10
when you already have the user, you can just do something like this:
var listing = req.user.userListings.id(req.params.listingId);
listing.isRead = args.isRead;
listing.isFavorite = args.isFavorite;
listing.isArchived = args.isArchived;
req.user.save(function (err) {
// ...
});
as found here: http://mongoosejs.com/docs/subdocs.html
Finding a sub-document
Each document has an _id. DocumentArrays have a special id method for looking up a document by its _id.
var doc = parent.children.id(id);
* * warning * *
as #zach pointed out, you have to declare the sub-document's schema before the actual document 's schema to be able to use the id() method.
Is this just a mismatch on variables names?
You have user.userListings[i].listingId in the for loop but user.userListings[i]._id in the find.
Are you looking for listingId or _id?
You have to save the parent object, and markModified the nested document.
That´s the way we do it
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
Profile.findById(req.params.id, function (err, profile) {
if (err) { return handleError(res, err); }
if(!profile) { return res.send(404); }
var updated = _.merge(profile, req.body);
updated.markModified('NestedObj');
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.json(200, profile);
});
});
};