I'm pretty new to Node.js and I'm starting a new web app just to study.
So, I'm using Mongoose.js and this is my model:
The party schema:
var PartySchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true
},
createdBy: {
type: Schema.ObjectId,
ref: 'User'
},
invitations: [{
type: Schema.ObjectId,
ref: 'Invitation'
}]
});
The Invitation schema:
var InvitationSchema = new Schema({
party: {
type: Schema.ObjectId,
ref: 'Party'
}
});
Ok,
So I wrote a test case like this, assume the other variable (party) is correctly initialized:
invitation = new Invitation({
party: party,
content: 'come to this awesome party'
});
When I pass this variable invitation to a method like this:
return Party.sendInvitation(invitation, function(err, invitation) {
should.exist(invitation);
should.not.exist(err);
done();
});
Accessing invitation.party inside the sendInvitation method is like this:
invitation.party[525439f929cf32be02000003]
As seem, I can't navigate through invitation.party.
How can I achieve this invitation.party.title?
I appreciate any help!
For test case, I think you can use data from query invitation with populate data from party.
Invitation
.findById(id)
.populate('title')
.exec(function (err, invitation) {
if (!err)
return invitation; //this invitation data must be contained party with title. invitation.party.title
})
Related
I am trying to build a kanban as a project for my portfolio with the mern stack with a rest api. I am having issues querying the models with deeply nested objects in it. My idea is to have the lists be referenced in the project, the task be referenced in the list and the user be referenced in the task and the project as a contributor. My issue is getting the information of the task (title, etc.) through populating the project model with mongoose, or MongoDB for that matter. How should I approach this? Is it even possible to do with MongoDB? I see a lot of people doing this with a sql database. The four model schemas are as follows:
const projectSchema = new Schema({
title: { type: String, required: true, max: 32, trim: true },
lists: [{ type: Schema.Types.ObjectId, ref: 'List' }],
contributors: [{ type: Schema.Types.ObjectId, ref: 'User' }],
});
const listSchema = new Schema({
title: { type: String, required: true, max: 32, trim: true },
tasks: [{ type: Schema.Types.ObjectId, ref: 'Task' }],
});
const taskSchema = new Schema({
title: { type: String, required: true, max: 38, trim: true },
text: { type: String, max: 255, trim: true },
assignee: { type: Schema.Types.ObjectId, ref: 'User' },
});
const userSchema = new Schema(
Name: { type: String, required: true, trim: true },
projects: [{ type: Schema.Types.ObjectId, ref: 'Project' }],
tasks: [{ type: Schema.Types.ObjectId, ref: 'Task' }],
);
The issue I have is displaying the tasks in the list. When I populate the list with the project call, I get the ObjectId of the task, but would like to get the task title, which as it seems is not possible by applying the .populate call again. I have the following api controller/route:
router.get('/:projectId', async (req, res) => {
try {
const project = await Project.findOne({
_id: req.params.projectId,
}).populate('lists', 'title tasks');
res.json(project);
} catch (error) {
if (error) {
console.error(error.message);
res.status(500).send('Server Error');
}
}
});
How would I approach getting the task title and later on the user name for all the tasks in the list referencing a project?
So I found a solution to this. Not sure if this is the most efficient method to solve this. If anyone can provide a better solution, please post it on here.
I found the mongoose documents explains quite well how to populate over multiple levels.
https://mongoosejs.com/docs/populate.html#deep-populate
Now the solution for the answer looks as follows
router.get('/:projectId', async (req, res) => {
try {
const project = await Project.findOne({
_id: req.params.projectId,
}).populate({ path: 'lists', populate: { path: 'tasks' } });
res.json(project);
} catch (error) {
if (error) {
console.error(error.message);
res.status(500).send('Server Error');
}
}
});
can someone help me with a mongoose operation? I'm currently building this voting system.
I have this Poll model as:
var Poll = new Schema({
title: {
type: String,
required: true
},
options: [{text:String, count: {type: Number, default: 0}}],
author: {
type: Schema.ObjectId,
ref: 'Account',
},
disabled: {
type:Boolean,
default: false,
},
date: {type: Date, defalut: Date.now},
});
and I have this Log model as:
var Log = new Schema({
ip: String,
voter: {
type: Schema.ObjectId,
ref: 'Account'
},
poll: {
type: Schema.ObjectId,
ref: 'Poll'
},
date: {type: Date, defalut: Date.now},
});
each time a user vote for something , log will create something like:
{ ip: '::1',
voter: 5824e7c3b6e659459818004f,
poll: 58264b48f767f2270452b5cb,
_id: 58264b4cf767f2270452b5ce }
now should a user delete one of his poll, say 58264b48f767f2270452b5cb , I would like to also remove all the log documents that has same poll id in it.
I read some other answer and came up a middleware with
Poll.pre('remove', function(next){
var err = new Error('something went wrong');
this.model('Log').remove({poll: this._id}, function(err){
if (err) throw err;
})
next(err);
});
but it's not working at all.
what should I do? Thanks.
At the current state Model.remove() calls don't use hooks, why? Because a document could not be present in memory at time of the call, so would be necessary to query mongo first and then delete the doc to make sure a hook would work properly.
There's a CR for adding this behavior but is not implemented, yet.
So the current way to do this is to use something like:
myDoc.remove();
An example, this won't work:
var myAccount = new Account({
name: "jim"
})
var myPoll = new Poll({
question: "You like stuff?"
})
var myLog = new Log({
voter: myAccount,
poll: myPoll
})
myAccount.save()
.then(myPoll.save())
.then(myLog.save())
.then(Poll.remove({
question: "You like stuff?"
}, function(err) {
console.log(err)
}))
This will work instead:
myAccount.save()
.then(myPoll.save())
.then(myLog.save())
.then(myPoll.remove(function(err) {
console.log(err)
}))
Hello so I am making a basic app with users and posts.
I followed the mongoose documentation on population (http://mongoosejs.com/docs/2.7.x/docs/populate.html) and setup my Schemas so that the users and be connected to posts
var userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
email: String,
created_at: Date,
updated_at: Date,
admin: Boolean,
posts: [{ type: mongoose.Schema.ObjectId, ref: 'Post' }]
});
var postSchema = new mongoose.Schema({
_user : [{ type: mongoose.Schema.ObjectId, ref: 'User' }],
audioFile: { type: String, required: true },
imageFile: { type: String },
title: { type: String, required: true },
artist: { type: String, required: true },
start: { type: String, required: true },
stop: { type: String, required: true },
genre: { type: String, required: true },
tags: [{ type: String }]
});
app.get('/', function (req, res){
Post.find({}, function(err, allPosts){
if(!err){
res.render('main.njk', {
posts : allPosts,
title : 'Title',
isLogged : req.session.isLogged,
user : req.session.user,
messages : req.flash('alert')
});
} else { return done(err); }
});
});
Thats all fine and gravy and I can run a foreach loop on allPosts to pull each one in my HTML, but when I try to think of how I am going to display all the posts with their respective users attached to each post I am unsure of how to connect the two since all the examples in the mongoose doc is just mainly for findOne.
I was thinking something like this
app.get('/', function (req, res){
Post.find({}, function(err, allPosts){
if(!err){
allPosts.populate('_user', ['username']);
allPosts.exec(function (err, users){
if(err) console.log(err);
console.log(users);
});
res.render('main.njk', {
posts : allPosts,
title : 'Spaurk.net',
isLogged : req.session.isLogged,
user : req.session.user,
messages : req.flash('alert')
});
} else { return done(err); }
});
});
but that doesn't work of course.
So I was wondering if anyone with experience with this situation would be able to help me solve this.
Thanks a lot for any input.
EDIT, thanks to Daves help I was able to get the populate to work properly, I just cant pull the fields I want correctly with
Post.find({}).populate('_user').exec(function(err, allPosts){
In my loop {% for post in posts %}
, when I do post._user it shows the whole user schema, but when I do post._user.username it doesn't return anything. I am unsure as to why this is.
The proper way to structure a populate on a query is like this:
Post.find({})
.populate('_user')
.exec((err, allposts){...})
Then you will have an array of your Posts with the _user array populated. If you need to access a property of a user, you will need to do another loop through the _user array or specify with use you want to use _user[0].<property>
I have architectural question about how to design my meanjs controller and routes for mongoose subdocuments.
my model looks as following:
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
* Customerrpc Schema
*/
var CustomerrcpSchema = new Schema({
company: {
type: String,
enum: ['Option1', 'Option2'],
required: 'Please fill company name'
},
rcp: {
type: String,
required: 'Please fill rcp'
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
/**
* Customer Schema
*/
var CustomerSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Customer name',
trim: true
},
description: {
type: String,
default: '',
//required: 'Please fill Customer description',
trim: true
},
url: {
type: String,
default: '',
//required: 'Please fill Customer url',
trim: true
},
rcp: [CustomerrcpSchema],
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Customer', CustomerSchema);
mongoose.model('Customerrcp', CustomerrcpSchema);
I tried it out by adding on the server controller the following code during the create methode:
exports.create = function(req, res) {
var customer = new Customer(req.body);
customer.user = req.user;
var rcp = new Customerrcp({
company: 'Option1',
rcp: 'dumm',
user: req.user
});
customer.rcp = rcp;
customer.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(customer);
}
});
};
This works perfectly fine. Now my question is what is the best procedure to create / modify / remove a subdocument from the maindocument?
I thought of always work with the main document 'Customer' but this brings several issues with it that i dont like, like saving always the hole document. Since i do have a uniq _id for each subdocument i guess there must be a better way.
What i would like to have is a controller only for the subdocument with the create / save / remove statement for it. Is this even possible?
As far as i understand it:
to create a new subdocument i need the following: _id of the main document for the mongoose query. So i need a service which would handover the _id of the maindocument to the controller of the selected subdocument. I was able to do this.
But im insecure if this is the proper way.
Any Ideas?
Cheers,
Michael
I want to display friends of Authenticated user in angularjs page.
// Find a list of Friends
$scope.find = function() {
$scope.friends = Authentication.user.friends;
$scope.firstFriendName = Authentication.user.friends;
};
I'm using mongoose with nodejs.(MeanJS)
How can I populate friends of current user in meanjs?
Thanks.
Either extend the user object or add a custom model for example Person , that consists of both user reference, and list of friends:
/**
* Person Schema
*/
var PersonSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Person name',
trim: true
},
desc:{
type: String,
default: '',
trim: true
},
friends:[{
rate: Number,
date: Date
}],
,
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Person', PersonSchema);
Then write the corresponding controller and views. Or just use meanJS generators:
yo meanjs:crud-module Persons
Then add the appropriate changes to the module. By the way, there is a package for something similar that seems to patch the User schema: moongose-friends
var PersonSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Person name',
trim: true
},
desc:{
type: String,
default: '',
trim: true
},
friends:[{
type: Schema.ObjectId,
ref: 'User'
}],
,
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
Then you would use the populate() method built into Mongoose which MEANJS uses. You can actually see how this works if you use the generators to build a CRUD module. Then you can look at the express controller for a specific view and you will see how it uses populate() (this is pretty much what you will see for a list function in the express controller when you generate a crud module.
Friends.find().sort('-created').populate('user', 'displayName').exec(function(err, friends) {
// Handle error & return friends code here
});
Hope that helps. You would then want to look at the angular controller and view so that you could modify the object in the controller and reflect it in the view.