How to push to an array in mongoose - arrays

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 ...
}
});
}
});
);

Related

A nested array schema with object element returns an array with empty object

I want to have array of objects i.e teamMembers should be an array and should have object as its element with properties name and role.I do not receive any error, when I console.log(req.body), its in the format i want, but the the array element which is object is not be posted to the schema.
_id: mongoose.Schema.Types.ObjectId,
teamName: { type: String, unique: true },
teamMembers: {
name: {
type: String, unique: true, lowercase: true, required: true
},
role: {
type: String,
enum: ['goal keeper', 'central back', 'central midfield', 'central forward', 'left wing',
'attacking midfield', 'central forward', 'left midfielder', 'striker', 'defending', 'right midfielder'],
required: true
},
type: Array
},
description: String,
createdAt: { type: Date, default: Date.now() },
updatedAt: { type: Date, default: Date.now() }
});
teamSchema.plugin(uniqueValidator); ```
I am not getting the desired result. Here is my collection from mogodb
{
"_id":{"$oid":"5d89d5da3f33f36579bfed25"},
"teamMembers":[{}],
"createdAt":{"$date":{"$numberLong":"1569314251247"}},
"updatedAt":{"$date":{"$numberLong":"1569314251247"}},
"teamName":"Arsenal",
"__v":{"$numberInt":"0"}
}
Expected result
``` "teamMembers":[{"name": "bernd leno", "role": "goal keeper"}] ```
Gotten result ``` "teamMembers":[{}] ```
Here is my below
```static async addTeam(req, res) {
const {
teamName, teamMembers, description
} = req.body;
try {
if (!req.user.isAdmin) {
return response(res, 404, 'error', {
message: messages.unAuthorizedRoute
});
}
const teams = new TeamModel({
_id: new mongoose.Types.ObjectId(),
teamName,
teamMembers,
description
});
const team = await teams.save();
if (team) {
return response(res, 201, 'success', { team });
}
} catch (error) {
(error.errors.teamName.name === 'ValidatorError')
? response(res, 409, 'error', {
message: messages.duplicateName
})
: response(res, 400, 'error', {
message: messages.error
});
}
}```
My code is correct, I wasn't posting the array of objects correctly from postman.Right way to post an array of objects in postman using urlencoded
It also works with raw json/urlencoded
{
"teamName": "Arsenal",
"teamMembers": [{"name": "bernd leno", "role":"goal keeper"}, {"name": "Emiliano Martinez", "role":"goal keeper"}]
}

Mongoose - Cannot Update update deeply nested Objects

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");
});

Save current User into field within array in Mongoose

Here is a relevant part of my Schema, where I'll make reservations to a "space":
var spaceSchema = new mongoose.Schema({
spaceName: String,
scheduledDates: [{
scheduledDates: String,
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
username: String
}
}]
});
Author should be the current user that's logged in. Here is my route to update those fields:
router.put('/:space_id/schedule', function(req, res) {
Space.findByIdAndUpdate(req.params.space_id, {
'$push': { 'scheduledDates': req.body.space, 'author': req.user._id }
}, { "new": true, "upsert": true }, function(err, space) {
if (err) {
console.log(err);
} else {
console.log(req.body.space);
}
});
});
I can't access "author" correctly, because it's inside the array. What can I do to update this array, adding a new date and user to make the reservation?
Thank you
UPDATE
I tried to use "_id" instead of "id" in my property but got the same result. It seems like it's ignoring the "author" field, and only saving "scheduledDates"
So the schema was like this:
scheduledDates: [{
scheduledDates: String,
author: {
_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
username: String
}
}]
And then in my route, I changed what I was 'pushing':
'$push': { 'scheduledDates': req.body.space, 'author._id': req.user._id }
UPDATED 2
Changed the way I was getting the object to push:
'$push': {
'scheduledDates': {
'scheduledDates': req.body.space,
'author': { _id: req.user._id, username: req.user.username }
}
}
Now I'm getting the following error:
message: 'Cast to string failed for value "{ scheduledDates: \'04/11/2017\' }" at path "scheduledDates"',
name: 'CastError',
stringValue: '"{ scheduledDates: \'04/11/2017\' }"',
kind: 'string',
value: [Object],
path: 'scheduledDates',
reason: undefined } } }

Mongoose: 'Cast to embedded failed for value at path. Cannot use 'in' operator to search for '_id'

I'm having some trouble trying to save an array inside an array of objects.
I'm getting the following response from the server:
{ [CastError: Cast to embedded failed for value "\'maxbeds: 4\'" at path "saved_searches"]
message: 'Cast to embedded failed for value "\\\'maxbeds: 4\\\'" at path "saved_searches"',
name: 'CastError',
kind: 'embedded',
value: '\'maxbeds: 4\'',
path: 'saved_searches',
reason: [TypeError: Cannot use 'in' operator to search for '_id' in maxbeds: 4] }
Here's my Schema:
var mongoose = require('mongoose'),
rfr = require('rfr'),
passwordHelper = rfr('server/helpers/password.js'),
Schema = mongoose.Schema,
_ = require('lodash');
/*
*
* Creating UserSchema for MongoDB
*
*/
var UserSchema = new Schema({
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true,
select: false
},
name: {
type: String,
required: true
},
passwordSalt: {
type: String,
required: true,
select: false
},
saved_houses: [{
mlsId: {
type: String
},
addressFull: {
type: String
},
bedrooms: {
type: Number
},
listPrice: {
type: Number
},
bathrooms: {
type: Number
},
sqft: {
type: Number
},
createdAt: {
type: Date,
default: Date.now
}
}],
saved_searches: [{
search_name: {
type: String
},
filters: {
type: [Schema.Types.Mixed]
},
createdAt: {
type: Date,
default: Date.now
}
}],
active: {
type: Boolean,
default: true
},
createdAt: {
type: Date,
default: Date.now
}
});
// compile User model
module.exports = mongoose.model('User', UserSchema);
The problem, I believe is the filters array that live inside an object inside the saved_searches array
Now, in my router I do the following:
var express = require('express'),
savedDataRouter = express.Router(),
mongoose = require('mongoose'),
rfr = require('rfr'),
s = rfr('server/routes/config/jwt_config.js'),
User = rfr('server/models/User.js'),
jwt = require('jsonwebtoken');
savedDataRouter.post('/searches', function (req, res) {
if (mongoose.Types.ObjectId.isValid(req.body.userId)) {
User.findByIdAndUpdate({
_id: req.body.userId
}, {
$push: {
saved_searches: {
search_name: req.body.search_name,
$each: req.body.filters
}
},
}, {
new: true
},
function (err, doc) {
if (err || !doc) {
console.log(err);
res.json({
status: 400,
message: "Unable to save search." + err
});
} else {
return res.json(doc);
}
});
} else {
return res.status(404).json({
message: "Unable to find user"
});
}
});
If I log the request body coming from the client I get the following:
//console.log(req.body)
{ search_name: 'Sarasota',
filters: [ 'minbaths: 1', 'maxbaths: 3', 'minbeds: 2', 'maxbeds: 4' ],
userId: '583359409a1e0167d1a3a2b3' }
I've tried all the things I've seen in Stack Overflow and other online resources with no luck. What am I doing wrong?
Edit
Added module dependencies to my UserSchema and SavedDataRouter
try this
User.findByIdAndUpdate({
_id: req.body.userId
}, {
$push: {
saved_searches: {
search_name: req.body.search_name,
filters: req.body.filters
}
},
}, {
new: true
},
function (err, doc) {
if (err || !doc) {
console.log(err);
res.json({
status: 400,
message: "Unable to save search." + err
});
} else {
return res.json(doc);
}
});

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);
});
});

Resources