Mongoose: Using the same schema in two separate arrays - node.js

I have two schemas, defined as following:
var userSchema = new Schema({
email: String,
name: String,
role: String,
password: String
})
var raceSchema = new Schema({
date: Date,
name: String,
location: String,
time: String,
register: String,
participants: [{ type: Schema.Types.ObjectId, ref: 'User'}],
registered_participants: [{ type: Schema.Types.ObjectId, ref: 'User'}],
})
As you can see, I reference the first schema twice in the second schema. If I add a reference to a user in one of the lists, everything is fine. But when I add a reference to the same user to the other list I get the following error: Cast to [undefined] failed for value
What causes this error? Is it related to the fact that the same schema is used twice in the second schema?
Edit:
I get the error when I call the following Express endpoint:
app.post('/race/:id/registered', passport.authenticate('jwt', { session: false}), (req, res) =>
Race.findOne({ _id: req.params.id }, function (err, race) {
if (err) return res.json({'Error': err})
if (!race) return res.json({'Error': 'Race not found'})
race.registered_participants.push(req.user)
race.save(function (err, updatedRace) {
if (err) return res.json({'Error': err})
res.send(updatedRace)
})
})
)
Edit 2: The model definitions:
var User = mongoose.model('User', userSchema);
var Race = mongoose.model('Race', raceSchema);

Try using findByIdAndUpdate in your POST method instead:
app.post('/race/:id/registered', passport.authenticate('jwt', { session: false}), (req, res) =>
Race.findByIdAndUpdate(req.params.id,
{ $push: { registered_participants: req.user } },
function (err, race) {
if (err) return res.json({'Error': err})
res.send(race)
})
)

Related

Node express find and return response multple models

I'm fairly new to node & express, I'm trying to implement a register application.
I have 2 models, both models have one common field 'empID'.
const RegisterEntriesSchema = mongoose.Schema({
empID: Number,
registerType: String,
registerItemsQuantity: Number,
registerItemsDesc: String
}, {
timestamps: true
});
const RegisterEmpSchema = mongoose.Schema({
empID: Number,
empName: String,
empPhone: String,
empProj:String
}, {
timestamps: true
});
For my get call in which I need to merge the values, I get from RegisterEmpSchema with its corresponding
employee details from RegisterEmpSchema.
exports.findAllRegisterEntries = (req, res) => {
registerEntriesModel.find()
.then(result => {
var updatedResponse=[];
console.log(result[0].empID);
for(var i=0;i<result.length;i++){
registerEmpModel.find({ empID: result[i].empID })
.then(result2 => {
**//unable to access result here**
}).catch(err => {
console.log("exception catch called findAllRegisterEntries, find employee details "+err);
});
}
res.send(updatedResponse);
}).catch(err => {
res.status(500).send({
message: err.message || "Some error occurred while retrieving register."
});
});
};
I basically need to get register data and its corresponding employee data.
How do I modify my find() code to use the key empID and do a join query fetch?
I think you better use populate, add ref to empID inside RegisterEntriesSchema
const RegisterEmpSchema = new mongoose.Schema({
empID: Number,
empName: String,
empPhone: String,
empProj: String
}, {
timestamps: true
});
const registerEmpModel = mongoose.model('RegisterEmpSchema', RegisterEmpSchema, 'registerEmployeeCollection');
const RegisterEntriesSchema = new mongoose.Schema({
registerType: String,
registerItemsQuantity: Number,
registerItemsDesc: String,
empID: {
type: mongoose.Schema.Types.ObjectId,
ref: 'RegisterEmpSchema'
}
}, {
timestamps: true
});
RegisterEntriesSchema.index({ createdAt: 1 }, { expires: '525601m' });
const registerEntriesModel = mongoose.model('RegisterEntriesSchema', RegisterEntriesSchema, 'registerEntriesCollection');
module.exports = {
registerEmpModel, registerEntriesModel,
}
then use populate() to populate the RegisterEntriesSchema with correspondence empID
RegisterEntriesSchema.
find().
populate('empID').
exec(function (err, data) {
if (err) return console.log(err);
res.send(data);
});
check mongoose docs: https://mongoosejs.com/docs/populate.html

Why save() in mongoose is not a function?

I'm developing an app using Node.js, Mongoose, MongoDb, express.
I have 2 schemas one for student and one for snippets. I'm using the population model population model. I can create a user, and create a snippet and link it to the user. But I can't link and save the snippets in the user collection.
How to link and save the user so that it can have a reference to his snippets?
user and snippet schema
var userSchema = Schema({
name: { type: String, required: true, unique: true },
password: { type: String, required: true },
snippet: [{ type: Schema.Types.ObjectId, ref: 'Snippet' }]
})
var snippetSchema = Schema({
user: {type: Schema.Types.ObjectId, ref: 'User'},
title: String,
body: String,
createdAt: {
type: Date,
require: true,
default: Date.now
}
})
This is how I save the snippets I add it inside a user .save() function so that it saves the snippet ref but it gives me user.save() is not a function error.
var name = request.session.name.name
User.find({ name: name }).then(function (user) {
if (user) {
console.log('====================')
console.log(user)
user.save().then(function () { // problem is here?
var newSnippet = new Snippet({
user: user._id,
title: title,
body: snippet
})
newSnippet.save().then(function () {
// Successful
console.log('success')
response.redirect('/')
})
})
}
}).catch(function (error) {
console.log(error.message)
response.redirect('/')
})
But, I actually get the object printed after searching for it!
[ { _id: 5a2e60cf290a976333b19114,
name: 's',
password: '$2a$10$vD3EaQly4Sj5W3d42GcWeODuFhmHCSjfAJ1YTRMiYAcDBuMnPLfp6',
__v: 0,
snippets: [] } ]
You need to use User.findOne to get a valid user object, here you get an array. Also, don't forget to always return something in you promises (or throw an error).
Here is a quick rewrite of your function. With a few improvements such as arrow functions, const and a flat promise chain (never using any .then inside another .then) and avoiding code repetition
const name = request.session.name.name
User.findOne({ name })
.then(user => {
if (user) return user.save()
// What to do if not found? Throw an error?
throw new Error('User not found')
})
.then(() => {
const newSnippet = new Snippet({
user: user._id,
title: title,
body: snippet,
})
return newSnippet.save()
})
.catch((error) => console.log(error.message))
.then(() => response.redirect('/'))

How to use object id that give reference in nodejs mongodb

There is no another error but I want to know just one thing.How to use that give reference in User schema object _id it means location_id how to use when I add new User.
User Schema :
var userSchema = Mongoose.Schema({
name:{type: String,require:true},
surname: {type: String,require:true},
tel: {type: String,require:true},
age: {type: String,require:true},
mevki_id: {type: String,require:true},
location_id: { type: Mongoose.Schema.Types.ObjectId, ref: 'locations' }
});
Location schema:
var LocationSchema = Mongoose.Schema ({
il: {type: String, require:true},
ilce: {type:String, require:true}
});
UserController -- I add user here
this.createUser = function(req, res) {
var la=new Location({il:'istanbul',ilce:'camlica',location_id:la._id}).save(function (err) {
if (err) return handleError(err);
});
var user = new User({
name:'akif',surname:'demirezen',tel:'544525',age:'45',mevki_id:'2',
}).save(function (err) {
if (err) return handleError(err);
res.send(JSON.stringify(job));
});
}
There are several errors in your code. For example, the require property should be required.
Other problem is that you are setting the location_id value of la with a reference to la, that at that time has not been yet assigned a value.
Mongo will automatically create a field called _id: ObjectId on all your objects. Try this:
this.createUser = function(req, res) {
var la = new Location({
il:'istanbul',
ilce:'camlica',
}).save(function (err, location) {
if (err) return handleError(err);
var user = new User({
name:'akif',
surname:'demirezen',
tel:'544525',
age:'45',
mevki_id:'2',
location_id: location._id
}).save(function (err, user) {
if (err) return handleError(err);
// Warning: AFAIK job does not exist, should it be user?
res.send(JSON.stringify(job));
});
});
}

How to pass nested arrays from backend to frontend using Mongoose in Node.js?

This is my MongoDB schema:
var partnerSchema = new mongoose.Schema({
name: String,
products: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Product'
}]
});
var productSchema = new mongoose.Schema({
name: String,
campaign: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Campaign'
}
]
});
var campaignSchema = new mongoose.Schema({
name: String,
});
module.exports = {
Partner: mongoose.model('Partner', partnerSchema),
Product: mongoose.model('Product', productSchema),
Campaign: mongoose.model('Campaign', campaignSchema)
}
And I'd like to send all documents (partner>product>campaign) to my View as a one object.
I know how to send partner with product ref. For example:
var campSchema = require('../model/camp-schema');
router.get('/partner-list', function (req, res) {
campSchema.Partner.find({}, function (err, partnerList) {
if (err) throw err;
res.json({ partnerList: partnerList });
}).populate('products');
});
And I can easily iterate at view in this way:
li(ng-repeat="product in partner.products")
a(href="#") {{ product.name }}
And here is the question. How can I pass ONE object as a document with partner, product and campaign. Because at the moment I have only partner and product in that object.
You can use this pattern to populate the nested campaign model:
var campSchema = require('../model/camp-schema');
router.get('/partner-list', function (req, res) {
campSchema.Partner
.find({})
.populate({
path: 'products',
model: 'Product',
populate: {
path: 'campaign',
model: 'Campaign'
}
}).exec(function(err, partnerList) {
if (err) throw err;
res.json({ partnerList: partnerList });
});
});

Mongoose return populated array after save

I am trying to return an updated object as JSON, where the update was to set an array of objectIDs. I want the returned objected to have that array populated. For example, I have the following (simplified) model:
var UserSchema = new mongoose.Schema({
username: {type: String, unique: true, required: true},
friends: [{type: mongoose.Schema.Types.ObjectId, ref: 'User'}]
});
In my controller, I have:
exports.saveFriends = function(req, res) {
User.findById(req.params.user_id, function(err, user) {
// req.body.friends is JSON list of objectIDs for other users
user.friends = req.body.friends
user.save(function(err) {
user.populate({path: 'friends'}, function(err, ticket) {
if (err) {
res.send(err);
} else {
res.json(user);
}
});
});
});
}
This does in fact save the array properly as ObjectIDs, but the response user always shows "[]" as the array of friends.
Anyone see my issue?

Resources