Mongoose - Cannot Update update deeply nested Objects - arrays

var ItemSchema = new Schema({
item: {type: String, required: false},
ts: {type: String, required: true},
selldate: {type: Number, required: false},
replaced: [ReplaceSchema]
});
var ProductSchema = new Schema({
title: {type: String, required: true, trim: true}, //name of the products
artNo: {type: Number, required: true},
catId: {type: String, required: true},
productType: {type: String, required: true}, //physical, textbased or downloadable product | can be 'dl', 'txt', 'phy'
tid: {type: String, required: false}, //only needed for physical products for providing a tid
minItems: {type: Number, required: true},
ts: {type: Number, required: true}, // when was the product online
buyCount: {type: Number, required: true}, // baught how many times
description: {type: String}, //more about the product
price: {type: Number, required: true}, // how much?
discounts: [DiscountSchema], // discount objects
items: [ItemSchema],
images: [], // fullsize images of the product
thumbnails: [], // small preview images of the product
// isPublic: {type: Boolean, required: true}, // if product should be published or not
itemCount: {type: Number, required: false} // how many items exists on the product
});
var CategorySchema = new Schema({
name: {type: String, required: true},
ts: {type: Number, required: true},
products: [ProductSchema]
});
So you see its: Category -> products[] -> items[]
I want to update the Objects in items array in the database and set (at this time undefined field "selldate".
My code snippet for this looks like this:
Category.getProductOfCategory(productId, function(err, boughtProduct) {
if (err) {
res.send({
status: false,
data: err
})
} else {
// console.log('BoughtProduct: ', boughtProduct.products[0])
var bought = boughtProduct.products[0];
// console.log('theItem: ', bought.items.id(item._id));
bought.items.id(item._id).selldate = Date.now();
bought.save(function(err, results) {
if (err) {
res.send({
status: false,
data: err
})
} else {
// i is increased because we need it on line 5
// console.log('itemerr', err)
console.log('saved', results);
j++;
// the next() function is called when you
// want to move to the next item in the array
next();
}
});
}
});
But nothing is happening in the database. Im getting No errors but "results" is just undefined.
Can you please help me?
Update:
I have a solution BUT it works only on executing it once.. after that, its nothing happening again...
The Code:
Category.findById(catId, function (err, data) {
if (err) console.log(err);
data.products.id(productId).items.id(item._id).selldate = Date.now();
data.save(function (err, result) {
if (err) console.log(err);
j++;
next();
});
});

i have posted a sample program containing documents & sub-documents.
Kindly check this and let me know if you need additional information
Schema
const PostSchema = new Schema({
title : String
});
const HomeSchema = new Schema({
"name" : {
type : String,
required : true
},
"city" : {
type : String,
required : true
},
post : [PostSchema]
});
To Save document and subdocument
const cat = new HomeModel({
name: "tiger",
city : "africa",
post : [{
"title" : "tiger post"
}]
});
cat.save((user) => {
console.log("saved");
console.log(user);
})
.catch((err)=>{
console.log("err");
console.log(err);
});
To update document
HomeModel.update({name : "tiger"},{city : "china123"})
.then((home)=>{
console.log("updated");
console.log(home);
})
.catch((error) => {
console.log("error");
console.log(error);
});
To add new subdocument
HomeModel.findOne({name : "tiger"})
.then((home) => {
console.log("findone")
console.log(home);
home.post.push({"title" : "monkey"});
home.save();
})
.catch((err)=>{
console.log("error");
});
To update existing subdocument
method:1
HomeModel.findOne({name : "tiger"})
.then((home) => {
console.log("findone")
const tes=home.post.id("5a3fe65546c99208b8cc75b1");
tes.set({"title" : "it workssdfg"});
home.save();
})
.catch((err)=>{
console.log("error");
});
To find parent document using sub-document id
HomeModel.findOne({"post._id" : "5a3fe65546c99208b8cc75b1"})
.then((home) => {
console.log("findone")
console.log(home);
})
.catch((err)=>{
console.log("error");
});

Related

How to validate array size on update with mongoose

I have this model on mongoose
const WorkOrderSchema = new Schema({
title: {
type: String,
required: 'Enter a title for the order'
},
description: {
type: String,
required: 'Enter a description for the order'
},
deadline: {
type: Date,
required: 'Enter a deadline for the order'
},
workers: [{ type: Schema.Types.ObjectId, ref: "Worker" }]
});
WorkOrderSchema.path('workers').validate(function(workers) {
if(workers.length > 5){return false}
return true;
}, 'Too many workers');
module.exports = mongoose.model('Orders', WorkOrderSchema);
and this code that assigns workers to the order.
exports.assign_a_worker = function(req, res) {
Order.update({"_id": req.params.orderId},
{"$addToSet": {"workers": req.params.workerId}},
{runValidators: true},
function (err, order) {
if (err)
res.send(err);
res.json(order);
}
);
};
However it doesn't validate the number of workers in the array and allows me to add unlimited objects to the workers array in the model. Not really sure what's going wrong.

Insert new values in array in mongoose

Below code contains two schema now Grocery Schema contains array of users in which i want to store all users id which are related to itemName
I have no clue how to insert new values in mongodb
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var GrocerySchema= new Schema({
itemName: {
type: String,
required: true,
unique: true
},
completed: Boolean,
date: String,
users:[{user_id:{type:Schema.Types.ObjectId,ref:user}}]
});
grocerydata=mongoose.model('grocery',GrocerySchema);
var UserSchema = new Schema({
fname: {
type:String,
required:true
},
lname:{type:String},
email: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
}
});
module.exports = mongoose.model('User', UserSchema);
I have used below code for saving the multiple values and set the value of array
var docs= {
itemName : req.body.item,
completed: true,
date: new Date(),
$push: {"users": {user_id: req.body._id}}
}
}
grocerydata.create(docs, function(err, results) {
if (err)
res.send(err);
console.log(results);
});
but I am not able to push the user_id in Grocery Please help me
Thanks in Advance!!
You have an error in your last snippet of code. var docs should be the following:
var docs={
itemName : req.body.item,
completed: true,
date: new Date(),
//you forgot to wrap $push in {}
{$push: {"users": {user_id: req.body._id}}}
}
Source

Getting user details in other schema[mongoose]

I'm getting my hands on mean stack development. I'm kinda stuck where my requirement is to get posted by functionality. I'm trying to build a simple classified ads app where a user adds/updates/deletes a classified. I'm able to do all of these but now I need to display the name of that particular user on that add who is logged in. I've researched online but couldn't get the solution.
My schema
var UserSchema = new Schema({
username: { type: String, required: true, unique: true },
firstName: { type: String, required: true },
lastName: { type: String, required: true },
email: { type: String, required: true, unique: true, lowercase: true },
phone: { type: Number, min: 10, unique: true },
hash: String,
salt: String
});
var ClassifiedSchema = new Schema({
title: { type: String, required: true, unique: true },
description: { type: String, required: true, },
price: { type: Number, required: true },
created: { type: Date, default: Date.now },
updated: { type: Date, default: null },
contact: {
name: String,
phone: Number,
email: String
},
image: String,
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
});
My route
router.route('/classifieds')
.post(function(req, res) {
var classified = new Classified(req.body);
classified.save(function(err, classified) {
if (err)
res.send(err);
res.json(classified);
});
})
.get(function(req, res) {
Classified.find(function(err, classifieds) {
if (err)
res.send(err);
res.json(classifieds);
});
});
router.route('/register')
.post(function(req, res) {
if (!req.body.username || !req.body.password || !req.body.email || !req.body.firstName || !req.body.lastName) {
return res.status(400).json({message: 'Please fill all the fields!'});
};
var user = new User(req.body);
user.setPassword(req.body.password);
user.save(function(err, user) {
if (err)
res.send(err);
res.json({ token: user.generateJWT()});
});
});
router.route('/login')
.post(function(req, res) {
if (!req.body.username || !req.body.password) {
return res.status(400).json({ message: 'Please fill all the fields!' });
};
passport.authenticate('local', function(err, user, info) {
if (err)
res.send(err);
if (user) {
return res.json({ token: user.generateJWT() });
} else {
return res.status(401).json(info);
};
})(req, res);
});
I want to know how do I get the username while posting the classified? I'm aware of the populate function but I've tried it and it doesn't seem to work.
Update
I've added my register and login route to show you the use of passport.
If you have an authentication system like passport which sets req.user to current logged in user, then:
.get(function(req, res) {
Classified.find({user: req.user},function(err, classifieds) {
if (err)
res.send(err);
res.json(classifieds);
});
});

MongoDB: Check to see if object is in array before before updating entry

Forgive me as I'm pretty new to Mongoose and MEAN in general.
I am curious if an if statement like this would work to prevent a user from pushing themselves into an array twice.
Right now I'm using ng-hide to hide the 'attend' button, but I'd like to learn of a way to prevent it altogether in mongoose.
export function attending(req: express.Request, res: express.Response, next: Function){
if(req.params.id.attending.indexOf(req['payload']._id) !== -1) {
Event.update({_id: req.params.id}, {$push: {'attending': req['payload']._id }, $inc: {numGuests: -1}}, (err)=> {
if (err) return next (err)
User.update({user}, {$push: {'attending': event}}, (err)=> {
if(err) return next (err);
res.json({message: "You're In!"});
})
});
}
}
Here is the model
let eventSchema = new mongoose.Schema({
title: {type: String, required: true},
name:{type: String, required: true},
eventAddress: { type: String, required: true},
dateCreated: {type: Number},
eventCreator: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
attending: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User'}]
});
Thanks for any suggestions!

How to push to an array in mongoose

I have this code:
router.post('/setsuggestions', function(req, res, next){
if(!req.body.username || !req.body.challengessuggestions){
return res.status(400).json({message: challengessuggestions});
}
var query = { username: req.body.username };
/*User.findOneAndUpdate(query, { challengessuggestions: req.body.challengessuggestions }, callback = function(response){
res.json(response);
});*/
/*
User.findOneAndUpdate(
query,
{$push: {"challengessuggestions": {$oid: req.body.challengessuggestions}}},
callback = function(response) {
res.json(response);
}
);*/
User.findOneAndUpdate(
query,
{$push: {challengessuggestions: req.body.challengessuggestions}},
{safe: true, upsert: true},
function(err, model) {
res.json(err);
}
);
});
When I postman like this:
I get the following error:
{ "name": "MongoError", "message": "exception: The field
'challengessuggestions' must be an array but is of type OID in
document {_id: ObjectId('56263b910d1a2f1f0077ffae')}", "errmsg":
"exception: The field 'challengessuggestions' must be an array but is
of type OID in document {_id: ObjectId('56263b910d1a2f1f0077ffae')}",
"code": 16837, "ok": 0 }
This is the schema definition of AppUser:
var UserSchema = new mongoose.Schema({
username: { type: String, lowercase: true, unique: true },
firstname: { type: String},
lastname: { type: String},
difficulty: { type: String},
isstudent: { type: Boolean },
haschildren: { type: Boolean},
gender: { type: String },
email: { type: String, unique: true},
birthdate: String,
isdoingchallenges: { type: Boolean },
challengescompleted: [{ type: ObjectId, ref: 'Challenge' }],
currentchallenge: { type: ObjectId, ref: 'Challenge' },
challengessuggestions: [{ type: ObjectId, ref: 'Challenge' }],
hash: String,
salt: String
});
This is the schema definiton of challenge:
var Challengeschema = new mongoose.Schema({
name: { type: String, initial: true, required: true, index: true },
image: { type: Array },
difficulty: { type: String },
studentfriendly: { type: Boolean },
childfriendly: { type: Boolean },
description: { type: String }
});
I'm sending this in the function that calls the api:
Object {_id: "5631423f8c5ba50300f2b4f6", difficulty: "medium", name:
"Probeer 1 van onze recepten.", __v: 0, childfriendly: true…}
This gives me following error:
D:\Stijn\Documenten\EVA-project-Groep-6\Api\node_modules\mongoose\lib\schema\obj
ectid.js:134
throw new CastError('ObjectId', value, this.path);
^ Error
at MongooseError.CastError (D:\Stijn\Documenten\EVA-project-Groep-6\Api\node
_modules\mongoose\lib\error\cast.js:18:16)
at ObjectId.cast (D:\Stijn\Documenten\EVA-project-Groep-6\Api\node_modules\m
ongoose\lib\schema\objectid.js:134:13)
at Array.MongooseArray.mixin._cast (D:\Stijn\Documenten\EVA-project-Groep-6\
Api\node_modules\mongoose\lib\types\array.js:124:32)
at Array.MongooseArray.mixin._mapCast (D:\Stijn\Documenten\EVA-project-Groep
-6\Api\node_modules\mongoose\lib\types\array.js:295:17)
at Object.map (native)
at Array.MongooseArray.mixin.push (D:\Stijn\Documenten\EVA-project-Groep-6\A
pi\node_modules\mongoose\lib\types\array.js:308:25)
at Query. (D:\Stijn\Documenten\EVA-project-Groep-6\Api\routes\ind ex.js:144:44)
at D:\Stijn\Documenten\EVA-project-Groep-6\Api\node_modules\mongoose\node_mo
dules\kareem\index.js:177:19
at D:\Stijn\Documenten\EVA-project-Groep-6\Api\node_modules\mongoose\node_mo
dules\kareem\index.js:109:16
at doNTCallback0 (node.js:408:9)
at process._tickCallback (node.js:337:13) 29 Oct 22:05:38 - [nodemon] app crashed - waiting for file changes before starti ng...
How do I solve this?
Query the User user using findOne() first and use the first found document that's passed to the callback to save the embedded documents with:
router.post('/setsuggestions', function(req, res, next){
if(!req.body.username || !req.body.challengessuggestions){
return res.status(400).json({message: challengessuggestions});
}
var query = { username: req.body.username };
User.findOne(query, function (err, user){
if (err) //throw ...
if (user) {
if (user.challengessuggestions && user.challengessuggestions.length) {
user.challengessuggestions.push(req.body.challengessuggestions);
}
else {
user.challengessuggestions = [req.body.challengessuggestions];
}
// save changes
user.save(function (err) {
if (!err) {
// done ...
}
});
}
});
);

Resources