Return the value from a mongoose find - node.js

I'm trying to render a template when i check the link for view a profile (for example going to http://localhost:3000/user/testuser`), all ok going to the routes but the values don't being showed on the page. This is my code:
Account.find({ username: req.params.username }, function(err, userWatch){
res.render('account/profile',{
title : userWatch.username,
user : req.user,
watchUser : userWatch,
});

You are using Account.find() that returns the array of objects. You should use Account.findOne() to fetch data, if you want either one or none objects.

Related

Express, Mongoose, db.findOne always returns same document

I am attempting a CRUD app with MEAN stack. I am using mongoose in Express to call to the MongoDB. I am using the FindOne function with a specified parameter, and it's always returning the same (incorrect) document.
I know I am connected to the correct database, since I get a document back from that collection, but it's always the same document, no matter what I pass as the parameter.
module.exports = mongoose.model('Player', playersSchema, 'players'); //in player.js
const Player = require('./model/players');
app.get('/api/player/:id', (req, res) =>{
Player.findOne({id: req.params.playerId},
function(err, player) {
if(err) {
res.json(err);
}
else {
res.json(player);
}
});
});
I have 3 separate "players", with three distinct "playerID" fields (38187361, 35167321, 95821442). I can use Postman to GET the following URL, for example:
http://localhost:3000/api/player/anythingyouWantInHere
and it will return 38187361, the first document. I've been over this website, many tutorials, and the Mongoose documentation and I can't see what I'm doing wrong..
I'd like to eventually find by playerId OR username OR email, but one hurdle at a time...
From the mongoose documentation of findOne, if you pass Id a null or an empty value, it will query db.players.findOne({}) internally which will return first document of the collection everytime you fetch. So make sure you are passing non-empty id here.
Note: conditions is optional, and if conditions is null or undefined,
mongoose will send an empty findOne command to MongoDB, which will
return an arbitrary document. If you're querying by _id, use
findById() instead.
Your route is '/api/player/:id', so the key on the req.params object will be 'id' not 'playerId'.
I don't know what/where/if you're populating the playerId param, but if you update your query to call req.params.id it should actually change the document based on the path as you seem to be wanting to do.
I had the same problem, and it was that the name of column's table was different from the model I had created.
In my model the name of the wrong column was "role" and in my table it was "rol".

Mongoose: How to find documents by sub-collection's document property value

I’m using Mongoose version 4.6.8 and MongoLab (MLab). I have a Mongoose schema called “Group” that has a collection of User subdocuments called “teachers”:
var GroupSchema = new Schema({
//…more properties here…//
teachers: [{
type: Schema.ObjectId,
ref: 'User'
}]
});
This is a document from the “groups” collection on MongoLab:
{
//…more properties here…//
"teachers": [
{
"$oid": "5799a9c759feea9c208c004c"
}
]
}
And this is a document from the “users” collection on MongoLab:
{
//…more properties here…//
"username": "bob"
}
But if I want to get a list of Groups that have a particular teacher (User) with the username of “bob”, this doesn’t work (the list of groups is empty):
Group.find({"teachers.username": "bob"}).exec(callback);
This also returns no items:
Group.find().where('teachers.username').equals('bob').exec(callback);
How can I achieve this?
Without some more knowledge of your set up (specifically whether you want anybody named Bob or a specific Bob whose id you could pick up first) - this might be some help although I think it would require you to flatten your teachers array to just their ID's, not single-key objects.
User.findById(<Id of Bob>, function(err, user){
Group.find({}, function(err, groups){
var t = groups.map(function(g){
if(g['teachers'].indexOf(user.id))
return g
})
// Do something with t
})
})
You can use populate to do that.
Try this:
Group.find({})
.populate({
path : 'teachers' ,
match : { username : "bob" }
})
.exec(callback);
populate will populate based on the teachers field (given path) and match will return only those who have username bob.
For more information on mongoose populate options, Please read Mongoose populate documentation.
I think the solution in this case is to get a teacher’s groups through the User module instead of my first inclination which was to go through the Groups module. This makes sense because it is in line with how modern APIs represent a one-to-many relationship.
As an example, in Behance’s API, an endpoint for a user’s projects is:
GET /v2/users/user/projects
And a request to this endpoint (where the User’s username is “matiascorea”) would look like this:
https://api.behance.net/v2/users/matiascorea/projects?client_id=1234567890
So in my case, instead of finding the groups by teacher, I would need to simply find the User (teacher) by username, populate the teacher’s groups, and use them:
User.findOne({username: 'bob'})
.populate('groups')
.exec(callback);
And the API call for this would be:
GET /api/users/user/groups
And a request to this endpoint would look like this:
https://example.com/api/users/bob/groups

Variables not showing content on Jade template

I am learning Node.js using a book. There was an example that as a learning experience I converted from what it was to a SQL version of it.
This single page is only intended to display user information. I load the user information on a middleware then pass it to the Jade template. Everything working up to this point.
When I want to render the template below, wherever I user content from the user object, it renders nothing.
h1= user.Name
h2 Bio
p= user.Bio
form(action="/users/" + encodeURIComponent(user.User), method="POST")
input(name="_method", type="hidden", value="DELETE")
input(type="submit", value="Delete")
To check if the object was without content, I added this 2 lines on the front
-console.log ( 'Inside Jade' )
-console.log ( user )
and the result in the console is:
Inside Jade
[ { Name: 'Jennifer Lopes',
User: 'jenny',
Password: 'asd',
Bio: 'Actress and singer' } ]
So this tells me that the information is there, but is not being rendered.
The code used to render the template is:
app.get ('/users/:name', loadUser, function ( req, res, next ) {
res.render ( 'users/profile', { title: 'User profile', user: req.user });
});
Can you please help me to understand what am I doing wrong? Thanks in advance.
A little hard to tell without seeing all your code, but per the output of your console it looks like user is actually an array of objects based upon the brackets, if you change your jade template to output something like user[0].Name does it give you your expected values?

Access mongoose non-schema values in Jade

I have a really weird problem in Jade where I cannot access the values that aren't defined in the Schema.
I'm using strict:false on my schema and saving values to it. My data looks like this:
{
"title" : "This is a title in the schema",
"notInSchema" : "This will never show up"
}
This works:
h1= post.title
This doesn't work:
h1= post.notInSchema
If I dump all my data into the template, I can see both pieces of data:
pre= JSON.stringify(options,null,'\t') //{"title" : "This is a title in the schema", "notInSchema" : "This will never show up"}
If I add notInSchema to my schema, it shows up. How can I do this without adding it?
Instead of passing the raw Mongoose document to Jade, pass its serialized version instead:
res.render('yourtemplate', {
post : post.toJSON() // .toJSON() is also called by JSON.stringify()
});
I believe Mongoose only creates accessors on a document for fields that are in the schema. Any other fields, even though they are stored in the database, don't get one so can't be accessed directly.
The documentation seems to suggest something similar:
NOTE: Any key/val set on the instance that does not exist in your
schema is always ignored, regardless of schema option.
EDIT: since you're dealing with result sets, you need to call toJSON on each document in it. The easiest way to do so is using map (hope I get the CF syntax right):
res.render "admin",
title : "Admin Dashboard"
results : results
users : results.users.map (user) ->
user.toJSON()
messages: req.flash() || {}
Although that would still leave results 'unprocessed'. Alternatively, you could leave the mapping to the separate steps in your async.series. For instance:
Company
.find()
.exec (err,companies)->
next(null,companies.map (company) ->
company.toJSON()
)
Or use toJSON in your template on any object that you need to access those "unschema'd" properties for.
I use:
model.find({Branch:branch},function (err, docs){
if (err) res.send(err)
res.render('index',
{tree: tree,
articulos: JSON.parse(JSON.stringify(docs))
})})
});

Extracting value from nested array in Mongoose

I'm working with Mongoose for the first time and I'm trying to accomplish what seems to be a simple task. I have a users document that contains a clients property, which consists of an array of client id's. As an example, my document looks like this:
{
email: "nick#movementstrategy.com",
password: "$2a$10$xZVzMYgyoyT.biOMDrBlRe3HNHY5A6lXga6uc8b/cnIAX/khQ7ep2",
modified: ISODate("2013-01-16T00:13:56.894Z"),
created: ISODate("2013-01-16T00:13:56.894Z"),
_id: ObjectId("50f5f0c4d6bbbcc6ce000002"),
clients: [
"50f6e118e0ccf9a1e9000001",
"50f6e12be0ccf9a1e9000002"
],
__v: 0
}
I've created a middleware that removes dependencies for a client when I call remove();
clientSchema.pre('remove', function(next) {
Sweepstakes.remove({client_id: this._id}).exec();
Submission.remove({client_id: this._id}).exec();
// find users with this._id present in clients, and remove from array
next();
});
Now, I simply need to locate all users who have the client id present in clients, remove the id, and update the user.
I know that I could easily query for all users with the id present, and then loop through and save out each user individually... But that seems inefficient, and my gut tells me that there is a better way to accomplish what I am trying to do -- just having a hard time locating it in the documentation.
What is the most efficient way to do this using Mongoose?
Probably something like this:
Users.update({condition}, {$pull : { clients: this._id} }, function(err, numAffected) {
//handle errors and whatever
next();
});
You can add clients : {$in : [this._id]} as condition to limit the update.

Resources