BrainTree node integration - node.js

I have the most Odd problem I have ever had. I just simple cannot find what is wrong with my code.
this is my user model
var userSchema = new Schema({
firstName: {type: String, required: true, trim: true},
lastName: {type: String, required: true, trim: true},
address: {
street: {type: String, required: true, trim: true},
city: {type: String, required: true, trim: true},
state: {type: String, min: 2, max: 2, required: false},
zipCode: {type: String, required: true, trim: true}
},
customerId: String,
subscription: {
id: String,
status: String,
planId: String,
price: Number,
nextBillingDate: Date
},
creditCard: {
token: {type: String, required: true}
},
email: {type: String, required: true, unique: true, trim: true},
password: {type: String, required: true, trim: true},
phone: {type: String, required: true, trim: true},
birthDate: {type: Date, required: true, trim: true},
role: {staff: Boolean, admin: Boolean, sAdmin: Boolean},
companies:[
{
type: Schema.Types.ObjectId,
ref: 'Company',
required: true
}
],
edited: {type: Date},
created: {type: Date, default: Date.now}
});
Now im creating a User Admin on my application with this code.
// BrainTree API
var nonce = req.body.payment_method_nonce;
gateway.customer.create({
firstName: user.firstName,
lastName: user.lastName,
company: req.body.compName,
email: req.body.email,
paymentMethodNonce: nonce
}, function (err, result) {
if(err) return handleError(err);
//NO ERROR FOUND
user.customerId = result.customer.id;
gateway.subscription.create({
paymentMethodToken: result.customer.paymentMethods[0].token,
planId: 'myId'
}, function (err, result) {
if(err){
throw err;
}
else {
//save subscription info
user.subscription.id = result.subscription.id;
user.subscription.status = result.subscription.status;
user.subscription.planId = result.subscription.status;
user.subscription.price = result.subscription.price;
user.subscription.nextBillingDate = result.subscription.nextBillingDate;
//transaction info
t.id = result.subscription.transactions[0].id;
t.amount = result.subscription.transactions[0].amount;
t.creditCard.maskedNumber = result.subscription.transactions[0].creditCard.maskedNumber;
t.created = result.subscription.transactions[0].createdAt;
saveAdmin();
}
});
now on user.customerId = result.customer.id;
I get this console error "Cannot read property 'id' of undefined", but that is not true. when I do a console.log(result.customer.id) I get the Id. I just don't know why is throwing the error.
I don't know if anybody can help me with this because but you never know.
Thanks in advance.

I solved the problem the return handleError(err) some how was executing the request twice. so I change the return handleError(err) with return console.error(err) and it solved the problem.

Related

How to make array ref in Mongoose

Here actually I want to make the service collection that contain the array of references of the ratings. when a user rate a service than an element is pushed in the array containing reference of user , service ID no and the rating.
Service Model like this:
var ServiceSchema = new Schema({
user_id:{
type: String,
required: [true, 'please provide user id']
},
name: {
type: String,
required: [true, 'please enter your name']
},
rating : [{ type: Schema.Types.ObjectId, ref: 'rating' }],
});
Rating schema:
var RatingSchema = Schema({
S_id : { type: Schema.Types.ObjectId},
Rating : Number,
By : { type: Schema.Types.ObjectId}
});
user schema:
var UserSchema = new Schema({
id: {
type: String,
unique: true,
required: [true, 'please enter your id']
},
password: {
type: String,
required: [true, 'please enter your password']
},
name: {
type: String,
required: [true, 'please enter your name']
},
type: {
type: [{
type: String,
enum: ['visitor', 'seller']
}],
default: ['visitor']
},
});
and I have defined the export as:
module.exports = mongoose.model('user', UserSchema, 'users');
module.exports = mongoose.model('service', ServiceSchema, 'service');
module.exports = mongoose.model('rating', RatingSchema, 'rating');
I want to make a function called rate but I am not getting how to make it.
exports.rate = function(req, res) {
var curr_service = new Service(req.body, result);
new_service.save(function(err, service) {
if (err)
res.send(err);
res.json(service);
});
};
So far I have done this.
Can someone help me to understand what should I do now? because I haven't find that much about mongoose to add ref in array...
In my case. This error was happening because instead of putting {es_indexed: true} inside the object declaration, I was putting it in the object that was using. For example:
const Client: Schema({
name: {type: String, es_indexed: true},
address: {type: Adress, es_indexed: true} //Wrong, causing error
})
Adress: Schema({
address: {type: String},
zipCode: {type: Number}
})
The correct way to use, is putting es_indexed: true into primitive types inside "Adress" schema declaration.
const Client: Schema({
name: {type: String, es_indexed: true},
address: {type: Adress} //Right way
})
Adress: Schema({
address: {type: String, es_indexed: true},
zipCode: {type: Number, es_indexed: true}
})
I hope it was helpful

Dynamic Mongoose Schema based on property

I have the following user schema (where all distinct properties of different user types are consolidated):
var UserSchema = new mongoose.Schema({
status: String,
firstName: String,
lastName: String,
address: Object,
email: {type: String, lowercase: true, unique: true, required: [true, "can't be blank"], match: [/\S+#\S+\.\S+/, 'is invalid'], index: true},
organization: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Organization' }],
phone: {type: Number, unique: true, required: true, required: [true, "can't be blank"]},
role: String,
hash: String,
salt: String,
deliverySchedule: [{type: String, required: true}]
}
"Common" Schema (what all user types share in common):
var UserSchema = new mongoose.Schema({
status: String,
firstName: String,
lastName: String,
email: {type: String, lowercase: true, unique: true, required: [true, "can't be blank"], match: [/\S+#\S+\.\S+/, 'is invalid'], index: true},
phone: {type: Number, unique: true, required: true, required: [true, "can't be blank"]},
role: String,
hash: String,
salt: String
}
Role = "Customer":
address: [{type: Object, required: true}]
Role = "DeliveryMan":
deliverySchedule: [{type: String, required: true}]
organization: [{ type: mongoose.Schema.Types.ObjectId, required: true,
ref: 'Organization' }],
Role = "Seller":
organization: [{ type: mongoose.Schema.Types.ObjectId, required: true,
ref: 'Organization' }],
I would like to add (and REQUIRE if possible) some fields to the "common" schema based on the user's role. However, I want to store them in the same collection.
How can I add a method to my models/Users.js to add properties to the schema based on "user.role"
Make require validation optional for each role dependent fields.
var UserSchema = new mongoose.Schema({
status: String,
firstName: String,
lastName: String,
email: {type: String, lowercase: true, unique: true, required: [true, "can't be blank"], match: [/\S+#\S+\.\S+/, 'is invalid'], index: true},
phone: {type: Number, unique: true, required: true, required: [true, "can't be blank"]},
role: {type: String, enum: ['Customer', 'DeliveryMan', 'Seller'], required: true},
address: {type: [Object], required: isRequired("address")},
deliverySchedule: {type: [String], required: isRequired("deliverySchedule")},
organization: { type: [mongoose.Schema.Types.ObjectId], ref: 'Organization', required: isRequired("organization")},
hash: String,
salt: String
});
function isRequired(field){
return function(){
if(field == "address"){
return this.role === "Customer"
}
else if(field == "deliverySchedule"){
return this.role === "DeliveryMan"
}
else if(field == "organization"){
return this.role === "Seller" || this.role === "DeliveryMan"
}
}
};

How to make some fields not updatable once saved in mongoose?

I have build a schema as follows:
const UserInfoSchema = new Schema({
email: { type: String, required: true, unique: true },
username: { type: String, required: true, unique: true },
userId: { type: Schema.Types.ObjectId, ref: 'User'},
displayName: { type: String, required: true },
profilePic: {
filename: {type: String},
url: {type: String}
},
created_at: Date,
updated_at: Date
})
What I need here is once the fields such as email, username and userId are saved, should not be modified. Is there anything pre-build in mongoose for this kind of feature?
I have done some research on schema.pre('update', (next) => {}), but got nothing really useful/don't know if one can use for the mentioned feature. Any help on this matter is greatly appreciated. Thanks in advance.
There is an easier way
when you save the Schema, you can set the field as immutable, like this
const UserInfoSchema = new Schema({
email: { type: String, required: true, unique: true, immutable:true },
username: { type: String, required: true, unique: true, immutable:true },
userId: { type: Schema.Types.ObjectId, ref: 'User', immutable:true},
displayName: { type: String, required: true },
profilePic: {
filename: {type: String},
url: {type: String}
},
created_at: Date,
updated_at: Date
})
it won't throw any error, if you want it you should check it elsewhere, but when you try to modify the immutable fields, it wont be changed at all
for(const key in userUpdates) {
switch(key) {
case 'username':
case 'email':
throw new Error('These field/s cannot be changed anymore');
}
}
User.findByIdAndUpdate(id, userUpdates, { new: true, runValidators: true });

Schema Association in Mongoose

I have 2 models:
Here is the User Model:
const userSchema = new mongoose.Schema({
email: { type: String, unique: true, required: true },
password: { type: String, required: true },
passwordResetToken: String,
passwordResetExpires: Date,
facebook: String,
twitter: String,
tokens: Array,
profile: {
name: String,
gender: String,
location: String,
website: String,
picture: String
}
}, { timestamps: true });
And here is the Revive Model:
const reviveSchema = new mongoose.Schema({
reviveShowName: {type: String, required: true},
reviveTitle: {type: String, required: true},
reviveCategory: {type: String, required: true},
reviveGoal: {type: Number, required: true},
revivePhoto: {type: String, required: true},
reviveVideo: {type: String},
reviveStory: {type: String},
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
name: String
}
}, { timestamps: true });
In the Revive model, I'm trying to the reference the author and get the author's id and that works... How do I also get the name from profiles -> name...? Clearly name: String is wrong...
Mongoose relations work, based on the ref and type value of the nested object. In your case you have associated the id property of author to point to the User model.
If you want to populate the author with the user information, you should just do :
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}
Then in your query you just use populate
Revive.find({})
.populate( 'author' )
.exec( function( error, docs ) {
console.log( docs ); // will have `[{author:{profile:{...}}}]` data
} );

Mongodb/Mongoose: one field will not updated by empty string

i am new in MongoDB/Mongoose and have the following problem:
my schema is nested with:
profile: {
school: {type: String, required: false},
subject: {type: String, required: false},
graduation: {type: String, required: false}
}
now i want to update school, subject and graduation with:
userRouter.put('/:id', function(req, res, next){
var updateObject = req.body;
User.findByIdAndUpdate(req.params['id'], updateObject,{upsert: true}, (err, success)=> {
if(err)
res.status(404).send(err);
res.status(200).send();
});
});
i know the put method replace the object, but the patch method doesn't run in my code. Now, when i sent:
{"school": "", "subject": "c", "graduation": ""}
subject and graduation will be overwritten, but school will not be empty - it contains the old stuff.
Do you have a solution? Thanks.
Tested like this school and graduation were modified...
let updateObject = {
profile: {school: "", subject: "c", graduation: ""}
};
user.findByIdAndUpdate(
req.params['id'],
updateObject,
{upsert: true},
function(err, success) {
if (err)
res.status(404).send(err);
res.status(200).send();
}
);
Used this testing schema:
new mongoose.Schema({
created: {type: Date, required: true, default: Date.now},
modified: {type: Date, required: true, default: Date.now},
profile: {
school: {type: String, required: false},
subject: {type: String, required: false},
graduation: {type: String, required: false}
}
},
{
collection: 'db_test',
strict: 'throw',
toJSON: {getters: true},
toObject: {getters: true}
}
);

Resources