How use a findOne query method in a custom instance method - node.js

I'm trying to do the following:
// Task Model
module.exports = {
schema: true,
attributes: {
directProy: {
type: 'string',
required: true
},
user: {
type: 'string',
required: true
},
checkUser: {
type: 'boolean',
defaultsTo: false
},
proy: {
type: 'string',
required: true
},
pieza: {
type: 'string',
required: true
},
hours: {
type: 'string',
required: true
},
obs: {
type: 'text',
defaultsTo: "lorem ipsum"
},
check: {
type: 'boolean',
defaultsTo: false
},
userName: function() {
User.findOne(this.user).done(function(err, user){
if(err){ return err;}
return user.name;
});
}
}
};
In the method "userName" I'm trying to get the name of a user with the ID it stored in the "user" attribute.
but when I run the "username" method, brings me back "undefined", I think this has to be a problem of asynchronous type
Would greatly appreciate the help they can give me since I have no idea how to associate values ​​between models and this is very useful

try passing a callback.
userName: function(cb) {
User.findOne(this.user).done(function(err, user){
cb(err, user.name);
});
}
Then when you are calling it, make sure to pass a callback.
model.userName(function(err, username) {
console.log(username);
});

your should use .exec instead of .done since it will not be avalible in sails#0.10
http://beta.sailsjs.org/#/documentation/reference/Models

Related

How can I get a `select: false` Schema objects value from the context of this in a schema.methods method?

tl;dr: If this isn't possible and User.findOne({username: this.username}).select('token') is the only way, then please let me know. Otherwise, I would like to know if there's another way to select select:false objects.
I have an email verification token that I only want to pull from my UserSchema object when an email verification endpoint is visited. (Other than that, I don't even necessarily want the object to exist in the database, but I don't know of a way to make a temporary value.) Inside of the context of this within a mongoose method, how can I select this value?
I also want to do the same thing for the password
Example:
const userSchema = new Schema({
username: {
//unique: true,
required: true,
type: String
},
password: {
required: true,
type: String,
select: false
},
email: {
required: true,
type: String,
unique: true
},
phone: {
required: true,
type: String
},
name: {
first: {
required: true,
type: String
},
last: {
required: true,
type: String
},
full: {
required: true,
type: String,
default: function() {
return `${this.name.first} ${this.name.last}`
}
},
},
email_verified: {
required: true,
type: Boolean,
default: false
},
token: {
type: String,
select: false
},
active: {
required: true,
type: Boolean,
default: true
},
created_date: {
required: true,
type: Date,
default: Date.now
},
updated_date: {
required: true,
type: Date,
default: Date.now,
}
},
{
timestamps: {
createdAt: 'created_date',
updatedAt: 'updated_date'
}
})
Methods in same file:
/* Code in question */
userSchema.methods.verify = async function(submittedToken, cb) {
try {
let user = this
/* I've tried this.select() and this.get() to no avail, seems like those only work with user.findOne() which I don't mind using, but would like to avoid if I can use this instead */
const token = user.token //undefined because of select:false
if(token != submittedToken) return cb({'Invalid token'})
return cb(null, user)
} catch (err) {
return cb(err, false);
}
}
userSchema.methods.authenticate = function(submittedPassword, cb) {
bcrypt.compare(submittedPassword, this.password, function(err, isMatch) {
if (err) return cb(err);
return cb(null, isMatch)
});
};
module.exports = mongoose.model('User', userSchema)
On a side note, do you guys recommend leaving the userId out of the email verification endpoint? It makes it easier to select the user, but not sure if it will cause security issues.
Total noob with Mongoose and not even sure if I'm approaching this professionally or securely, so all pointers welcome. Thanks guys.

I am facing issue with chaining .populate() method in mongoose

This is my user Schema where I have addresses as array
name: {
type: String,
unique: true,
require: true
},
email: {
type: String,
trim: true,
lowercase: true,
unique: true,
required: "Email address is required"
},
password: {
type: String,
required: true,
min: [6, "Password must be atlest 6 characters length"]
},
mobile: {
type: String,
required: true,
unique: true
},
image: {
type: String,
default: "gravatar.png"
},
addresses: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Address"
}
],
cart: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Cart"
}
],
orderHistory: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "OrderHistory"
}
]
});
This is post request to /user/address route where I want to create a new Address, link the user collection and address collection and populate the user collection. But it is giving me an error
"TypeError: Address.create(...).then(...).populate is not a function". I also used exec() method. I think I am not using populate and exec method correctly.
router.post("/address", function(req, res) {
console.log("form data: ", req.body);
Address.create(req.body)
.then(function(newAddr) {
// console.log(newAddr);
return User.findByIdAndUpdate(
{ _id: req.session.user._id },
{ $push: { addresses: newAddr._id } },
{ new: true }
);
})
.populate("addresses")
// .exec((err, updatedUser) => {
// if (err) {
// res.send(err);
// } else {
// console.log(updatedUser);
// res.redirect("/user");
// }
// });
.then(function(updatedUser) {
res.redirect("/user");
})
.catch(err => {
res.send(err);
});
});

How to generate hash password and store it in database in sails.js

I want to create new user and save into user table in my data base
i act as follows:
create: function(req,res,next){
bcrypt.hash(req.param('password'),10,function (err, hashed) {
if (err) {
console.log("4");
return res.serverError({'err': 'hash Error!'});
} else{
User.create({
username: req.param('username'),
password: hashed,
type: req.param('type')
},function (err, created_user) {
if (err) {
err = validator(User, err);
return res.json({'status': false, 'errors': err.Errors});
}
return res.json({'status': true, 'result': created_user});
}
);
}
}
}
My User Model is:
module.exports = {
attributes: {
username: {
type: 'string',
required: true,
unique: true
},
password: {
type: 'string',
required: true
},
type: {
type: 'number',
columnType: 'integer'
},
last_x_map: {
type: 'number',
columnType: 'float'
},
last_y_map: {
type: 'number',
columnType: 'float'
},
places :{
collection: 'place',
via: 'user_owner'
},
},
validationMessages: {
username:{
required: '...',
alphanumericdashed: '...',
unique: '...'
},
password: {
required: '...'
}
},
But it always return false and do not any thing.
Where is the problem?
Or what do you recommend for this?
thanks a lot.

How to implement many to many association using through in Sails?

I'm using Sails v0.11.2 and MongoDB 3.2 on Mac OS X El Capitan and I'm trying to implement Many-To-Many association using Through option which isn't supported yet.
However, googling I found this Waterline Github Issue and elennaro, a github user, gave me a couple of links with some examples:
First one
Second one
I have tried to adapt them to my own Sails app but I can't make it works. I got no errors on the console but the record or document on the intermediary table is not created only the Form document in it's table.
These are my models:
User.js
module.exports = {
schema: true,
tableName: 'users',
autoCreatedAt: false,
autoUpdatedAt: false,
attributes:
{
email : { type: 'email', required: true, unique: true },
encrypted_password : { type: 'string' },
reset_password_token: { type: 'string', defaultsTo: null},
permission_level : { type: 'integer', required: true, min: 1, max: 3, defaultsTo: 0 },
belongs_to : { type: 'string', required: true, defaultsTo: 0 },
signin_count : { type: 'integer', required: true, defaultsTo: 1 },
status_active : { type: 'boolean', required: true, defaultsTo: false },
last_signin_at : { type: 'datetime', defaultsTo: function (){ return new Date(); } },
last_signin_ip : { type: 'string', defaultsTo: '0.0.0.0' },
// Add a reference to Person
person_id:
{
model: 'person'
},
// Add a reference to Forms collection
forms:
{
collection: 'form',
via: 'user_id',
through: 'userhasform'
},
has:
{
collection: 'userhasform',
via: 'form_id'
}
}
};
Form.js
module.exports = {
schema: true,
tableName: 'forms',
attributes:
{
name : { type: 'string', required: true, unique: true },
creator : { type: 'string', unique: false },
sequence: { type: 'integer', autoIncrement: true },
// Add a reference to Questions collection
questions:
{
collection: 'question',
via: 'form_id'
},
// Add a reference to the owners Users
owners: {
collection: 'user',
via: 'form_id',
through: 'userhasform'
}
}
};
UserHasForm.js
module.exports = {
schema: true,
tableName: 'users_have_forms',
attributes:
{
to_edit : { type: 'boolean' },
to_delete : { type: 'boolean' },
user_id : { model: 'user' },
form_id : { model: 'form' }
}
};
The controller in which I create a form and it is supposed the intermediary document is been created at the join table is:
FormController.js
module.exports = {
create: function (req, res)
{
var ownerJson = {},
tmpFolio;
// Get the logged user to make the Folio and then create the form
SessionService.getUser(req, createForm);
// Callback function
function createForm (err, session)
{
// If there's no logged user or any error
if (err || !session)
{
console.log(err);
return res.json(err.status, {error: err});
}
console.log('User to create Folio: ', session.id);
ownerJson.owner_a = session.first_name;
ownerJson.owner_b = session.second_name;
ownerJson.owner_c = session.last_name;
// Construct the Folio creator part like AVC
tmpFolio = FolioService.generateFolio(ownerJson);
Form.create({
name: req.body.name,
creator: tmpFolio
})
.then(function (form){
if (err)
{
console.log(err);
return res.json(err.status, {error: err});
}
// Create the jointable record
var createdRecord = UserHasForm.create({
to_edit: true,
to_delete: true,
user_id: session.id,
form_id: form.id
})
.then(function (createdRecord){
if (err)
{
console.log(err);
return res.json(err.status, {error: err});
}
return createdRecord;
});
return [form, createdRecord];
})
.spread(function (form, createdRecord){
return res.json(200,
{
message: 'The form was created successfuly!',
data: form,
sharing: createdRecord
});
})
.fail(function (err){
if (err)
{
console.log(err);
res.json(err.status, {error: err});
}
});
}
},
};
When I run this code I got the next error:
[ReferenceError: UserHasForm is not defined]
Unhandled rejection TypeError: Cannot read property 'toString' of undefined
So I suppose it can't find the model so I add the next line to the model at the beginning:
var UserHasForm = require('../models/UserHasForm');
And now I get the next error:
[TypeError: UserHasForm.create is not a function]
All this is following the the first example on the list.
Any idea why I'm getting this error?
Any kind of help will be welcomed!
Well after trying to many examples finally I found the solution thanks to #elennaro for all his support. The whole conversation could be found in the link to the chat we both started under the main question's comments.
Also I can tell you that the examples in the links provided by him (which are in the question above) works fine, the problem was that the version I was using didn't support the features that those examples show.
Basically what I had to do is to install the most recent version for NodeJS, SailsJS and Waterline.
In my case I actually have the next ones:
Node v5.3.0
Sails v0.11.3
Waterline v0.10.30
After that I have to make some changes to my models and at the end they look like this:
User.js
module.exports = {
schema: true,
tableName: 'users',
autoCreatedAt: false,
autoUpdatedAt: false,
attributes:
{
// username : { type: 'string', unique: true, minLength: 5, maxLength: 15 },
email : { type: 'email', required: true, unique: true },
encrypted_password : { type: 'string' },
reset_password_token: { type: 'string', defaultsTo: null},
permission_level : { type: 'integer', required: true, min: 1, max: 3, defaultsTo: 0 },
belongs_to : { type: 'string', required: true, defaultsTo: 0 },
signin_count : { type: 'integer', required: true, defaultsTo: 1 },
status_active : { type: 'boolean', required: true, defaultsTo: false },
last_signin_at : { type: 'datetime', defaultsTo: function (){ return new Date(); } },
last_signin_ip : { type: 'string', defaultsTo: '0.0.0.0' },
// Add a reference to Forms collection
forms:
{
collection: 'form',
via: 'user',
through: 'userhasform'
// dominant: true
}
}
};
Form.js
module.exports = {
schema: true,
tableName: 'forms',
attributes:
{
name : { type: 'string', required: true, unique: true },
creator : { type: 'string', unique: false },
sequence: { type: 'integer', autoIncrement: true },
// Add a reference to the owners Users
owners: {
collection: 'user',
via: 'form',
through: 'userhasform'
}
}
};
UserHasForm.js
module.exports = {
schema: true,
tableName: 'users_have_forms',
attributes:
{
to_edit : { type: 'boolean' },
to_delete : { type: 'boolean' },
user : { model: 'User', foreignKey: true, columnName: 'user_id' },
form : { model: 'Form', foreignKey: true, columnName: 'form_id' }
}
};
FormController.js
Still the same as in the question
I hope it could be useful for anybody. And once again thanks to # Alexander Arutinyants for your support!
Any question, please leave a comment!

Sails js one to one populate conditions not working?

I'm newbie of Sails and I've got a problem with one to one association.
First, I have model User:
module.exports = {
schema: true,
identity : "User",
tableName: "user",
attributes: {
email: {
type: 'email',
unique: true,
required: true
},
password: {
type: 'string'
},
salt: {
type: 'string'
},
merchant: {
model: 'merchant',
defaultsTo: null
},
removed: {
type: 'boolean',
required: true,
defaultsTo: false
}
}
}
And my Merchant model:
module.exports = {
schema: true,
identity : "Merchant",
tableName: "merchant",
attributes: {
name: {
type: 'string',
unique: true,
required: true
},
code: {
type: 'string',
unique: true,
required: true
},
security_key: {
type: 'string',
required: true
},
active: {
type: 'boolean',
defaultsTo: false,
required: true
},
user: {
model: 'user'
}
}
}
So when I need to find records where merchant.active = true, I write this query:
var findUser = User.find(query).populate('merchant', {active: true});
return findUser;
But it was not working at all.
Anyone any ideas to solve this properly?
P.S. my Sails version is: 0.11.1. My DB is MongoDB
First of all, remove defaultsTo from your association attributes. I don't like this :) I don't know if it makes the problem, but in documentation I never see this.
Also you need to execute your query, not just return it. If I take your models' declarations then I can write populate query like this.
var findUser = User.find(query).populate('merchant', {active: true});
findUser.then(function(user) {
console.log('Your user is ' + user);
}).catch(function(error) {
console.log('Your error is ' + error);
});

Resources