I'm running into an issue with beforeValidate(), and can't find any answers online. My model has two relationship attributes that require id numbers in POSTed data. If a user POST strings instead, they get a validation error. I want to enable the user to POST string data, then inside beforeValidate() use findOrCreate() to find or create the attribute's related model, then overwrite the POSTed data's attribute with the relate model's ID.
I have the following model:
attributes: {
reporter : { model: 'reporter', required: true },
location : { model: 'location', required: true },
line : { type: 'boolean', required: true, defaultsTo: true },
count : { type: 'int', required: true, defaultsTo: 0},
composition : { type: 'int', required: true, defaultsTo: 3}
},
beforeValidate: function(values, next) {
if (typeof values.reporter !== 'number') {
Reporter.findOrCreate({name: values.reporter}).exec(function(data){
console.log(data)
values.reporter = data.id;
})
};
next();
},
I'm POSTing this data to the model's create() default blueprint endpoint:
{
"location":"Harry's",
"reporter":"tim",
"count":30,
"composition":3,
"line":false
}
When I log the above values inside beforeValidate(), I get this:
{ location: NaN,
reporter: NaN,
count: '30',
composition: '3',
line: false }
When I replace "location" and "reporter" with ID's, I don't get any errors. Why are the string values getting stripped out in the beforeValidate() function?
maybe u need POST(create) to endpoint location model, then POST(create) to reporter model, and then POST YOUMODEL/id/reporterID, POST YOUMODEL/id/location ID
Related
I'm developing an online store Node.js REST API with Mongoose (MongoDB), which I'm new to. I decided to test the orders service and saw that after I had made 1 successful order (so it worked once), it sent me a duplicate key error for the next one, for a key 'name' with value 'null', of the order.products collection that is an Array, and not a kvp object.
I should note that nowhere in my code is 'products.name' mentioned.
ERROR:
MongoServerError: E11000 duplicate key error collection: store.orders index: products.name_1 dup
at {...}{
key: { products.name: null }
index: 0,
code: 11000,
keyPattern: { 'products.name': 1 },
keyValue: { 'products.name': null },
[Symbol(errorLabels)]: Set(0) {}
}
when the error is handled, this message is received and it makes no sense:
{ "message": "Order with products.name "null" already exists" }
Order schema:
const schema = new Schema({
userId: {
type: Types.ObjectId,
ref: 'User'
},
address: {
type: addressSchema,
required: true
},
products: {
type: [orderProductSchema],
required: true,
validate: nonEmptyArray
},
status: {
type: Number,
validate: inCollection(Object.values(ORDER_STATUS))
},
price: { type: Number, required: true, min: 0 }
}, { timestamps: true });
don't bother with the validators or the address/status/user/price, it has nothing to do with them; what is more, nothing is specified as unique: true
As you can see, the 'products' field is just an array of products, no 'name' is declared
orderProductSchema:
const schema = new Schema({
product: {
_id: { type: Types.ObjectId, required: true },
name: {
type: String,
required: true,
maxLength: 250
},
displayImage: String,
price: { type: Number, required: true, min: 0 }
},
quantity: {
type: Number,
required: true,
validate: isInteger,
min: 1
},
}, { _id: false });
I have a 'name' field here, but it's just the name of a product. The error is thrown even when the names are unique.
Orders service:
// get data and format it to fit the Order model
console.dir(products); // --> all is how it's expected to be in the schema
return await Order.create({
userId,
address,
products,
status: ORDER_STATUS.AWAITING_CONFIRMATION,
price: totalOrderPrice
});
It seems to me that this is some weird MongoDB behaviour/specification that I missed. If someone has any idea what could cause the problem - please help.
I tried removing all parts such as other fields and validations to see if they might've caused the problem but that was not the case. I thought maybe I had formatted the object I send to the database wrong, but I console.log-ed it and it was fine ({products: Array})
Thanks to #user20042973 and #MTN I saw that my 'orders' database had index 'products.name' (no idea how it got there).. I just removed the index and the problem is solved.
I have an update call as below in my NestJs project to update a mongoose model.
async updateRole(role_id: ObjectId, request: any): Promise<any> {
return this.roleModel.findByIdAndUpdate(role_id, {...request});
}
Here is the request I'm passing
{
"name":"Super-Admin",
"application": "62b2dbfd82045f40ea884334",
"active":true,
"privileges": ["62b2dbfd82045f40ea884334","62b2dbfd82045f40ea884334"],
"updated_by": "Abhilash.Shajan1#gmail.com"
}
Below is my role schema
import * as mongoose from 'mongoose';
const Schema = mongoose.Schema;
const RoleSchema = new Schema({
name: {
type: String,
required: true
},
application: {
type: Schema.Types.ObjectId,
ref: 'Application',
autopopulate: true,
required: true
},
active: {
type: Boolean,
required: true
},
privileges: [{
type: Schema.Types.ObjectId,
ref: 'Privilege',
autopopulate: true
}],
created_by: {
type: String
},
created_at: {
type: Date
},
updated_by: {
type: String
},
updated_at: {
type: Date
}
});
RoleSchema.index( { name: 1, application: 1 }, { unique: true } );
export { RoleSchema };
I already created a document (This is the only document now present in the roles collection) with the above request. Now I'm trying to update its active field to true.
Since i have unique compound index in the schema, it does not allow me to update the active field, I'm getting unique contraint error on both application and name field.
This error will be meaningful if i have another document with same name and application in the collection, but there is not.
Another way is to pass the active field alone in the request. But it will not help in my case because the UI is always passing the whole fields which include the unchanged values as well.
Any suggestions ?
Hello community :) I implemented lots of good working functionality with firebase -> realm. Now i tried to edit a structure and I am running through the wildest error messages.
What is right for sure:
Firebase sends the data
Data is Converted (e.g. Firebase has "brands" as array -> is converted to a string for Realm Schema)
The error appears when firebase updates
Not every firebase content has all fields (e.g. Like you can see out of Realm Schema some fields are optional: true)
Fields where i maybe expect an issue:
Maybe its not possible to say that the ReferentList is optional (or i implemented it wrong): See Realm Schema const ReferentsList
What i tried
Debug before realm.create (Realm set) Result: Every data came in the right format
Checked all input values if they are int, string, ...
Hopefully someone can help me here because i got completely stuck with this issue and its necesarry to continue for my project. I want to know:
The solution why or what to do
A posibility to debug realm in a better way
Thank you in advance for your time and help :)
Error message: Value not convertible to a number
Firebase datastructure
"begin" : "2017-05-15T15:50:00.000Z",
"description" : "abc",
"end" : "2017-05-15T16:15:00.000Z",
"id" : 6,
"language" : [ 1 ],
"location" : "L 1.02",
"member" : 20,
"referent" : [ 1, 3 ],
"register" : true,
"title" : "Sound of Silence",
"track" : 6,
"type" : 3,
"brands" : [ 1, 2, 3 ]
Realm Schema
const ReferentListSchema = {
name: 'ReferentList',
properties: {
id: {
type: 'int',
optional: true
}
}
}
const LanguageListSchema = {
name: 'LanguageList',
properties: {
id: 'int'
}
}
const EventSchema = {
name: 'Events',
primaryKey: 'id',
properties: {
id: 'int',
begin: {
type: 'date',
optional: true
},
end: {
type: 'date',
optional: true
},
title: 'string',
description: 'string',
register: 'bool',
member: {
type: 'int',
optional: true
},
language: {
type: 'list',
objectType: 'LanguageList'
},
location: 'string',
referent: {
type: 'list',
objectType: 'ReferentList'
},
type: 'int',
track: {
type: 'int',
optional: true
},
img: {
type: 'string',
optional: true
},
brands:{
type: 'string',
optional: true
}
}
}
Realm set
set(obj) {
realm.write(() => {
if(obj.referent){
obj.referent = obj.referent.map(function(id) {
return {id};
})
}
if (obj.language){
obj.language = obj.language.map(function(id) {
return {id};
})
}
realm.create('Events', obj, true);
});
}
Solved:!
The issue got solved through wrong data at firebase. Some Date Objects hasent been set correct.
How i got to the solution
When i tried to debugg the code i made a try/catch block around:
try{
realm.create('Events', obj, true);
}catch(error){
console.log(obj);
console.log(error);
}
Through this debug i found the right data wich was wrong. Before it just showed me all objects and afterwards the error.
I wont close this question because of the chance to help someone with the same issues.-
So I've been at this for awhile and can't see how my code is different from the documentation.
I've also checked out this question, this question, this question, and this unanswered different question.
For my admin panel I'm trying to query to get all the information associated with a user and display a 'master' user profile to the admin.
My User model looks like this:
module.exports = {
autoPK: true,
attributes : {
id: {
type: 'integer',
primaryKey: true,
unique: true
},
email : {
type : 'email',
unique : true,
required : true,
},
password : {
type : 'string',
minLength : 8,
required : true
},
admin:{
type: 'bool'
},
user_profile:{
collection: 'userprofile',
via: 'user_id',
},
properties: {
collection: 'subjectproperties',
via: 'user_id'
},
employment_info: {
collection: 'employmentinfo',
via: 'user_id'
},
file_uploads: {
collection: 'fileupload',
via: 'user_id'
},
nearest_living_relatives:{
collection: 'nearestlivingrelative',
via: 'user_id'
},
mortgage_info: {
collection: 'mortgageinfo',
via: 'user_id'
},
user_progression_state:{
collection: 'userprogressionstate',
via: 'user_id'
},
users_applied_loan_values:{
collection: 'usersappliedloanvalues',
via: 'user_id'
}
}
}
I don't want to list out all the belongs to user models cause there are a lot of them, but here is one of the simpler one's.
EmploymentInfo.js
module.exports = {
tableName: "employment_info",
attributes : {
employers_name:{
type: 'string',
required: true
},
employers_address:{
type: 'string',
required: true
},
employers_city:{
type: 'string',
required: true
},
employers_state:{
type: 'string',
required: true
},
employers_zip:{
type: 'string',
required: true
},
job_position:{
type: 'string',
required: true
},
years_in_position:{
type: 'string',
required: true
},
years_in_industry:{
type: 'integer',
required: true
},
user_id:{
model:'user'
}
}
};
And as for my controller:
create_admin_user_profile: function(req, res){
var user_id = req.query.userId;
User.find({'id': user_id}).populateAll().exec(function(err, user){
if(err || user.length === 0){
sails.log.verbose(err);
}else{
sails.log.verbose(user);
}
});
},
It doesn't error out but all I see in the terminal is this for the above:
[ { user_profile: [],
properties: [],
employment_info: [],
file_uploads: [],
nearest_living_relatives: [],
mortgage_info: [],
user_progression_state: [],
users_applied_loan_values: [],
id: 5,
email: 'test#test.com',
admin: 1 } ]
Even though there is an entry in all of those tables for that user.
If I change the line:
User.find({'id': user_id}).populateAll().exec(function(err, user){
To:
User.find({'id': user_id}).populate('employment_info').exec(function(err, user){
Same but shorter result:
[ { employment_info: [],
id: 5,
email: 'test#test.com',
admin: 1 } ]
I've tried changing the case, I've tried adding columnName to the user_id attribute, I've tried changing the column name across the entire breadth of the project to not have an under_score in it, though that never seemed to be issue in it picking up the names correctly, but nothing I've done seems to work. I've also tried uninstalling sails, and the sails-mysql adapter and clearing my npm cache.
At this point my just stuck, I really can't see a reason why it's not working.
As for project info:
Sails v: 0.12.11
npm v: 3.10.9
node v: 7.2.0
Additional info asked for in comments:
SQL row taken right from db for user 5
employers_name, employers_address, employers_city, employers_state, employers_zip, job_position, years_in_position, years_in_industry, user_id
'Company', 'Mill Steet', 'SLC', 'Utah', '88888', 'Developer', '2', '2', '5'
And json format returned by find method in EmploymentInfo.js controller
{
"employmentInfo": {
"employers_name": "Company",
"employers_address": "Mill Steet",
"employers_city": "SLC",
"employers_state": "Utah",
"employers_zip": "88888",
"job_position": "Developer",
"years_in_position": "2",
"years_in_industry": 2,
"user": 5
}
}
The reason the last param is user and not user_id is because I rename it in the find method to serve the front-end mvc which also has the ability to work with associations. It's also why the JSON has the format it does.
Code from the find method that replaces user_id:
EmploymentInfo.find({'user_id': user_id}).exec(function(err, profile){
if(err || !profile.length){
return res.json(err);
}else{
res.status(200);
profile[0].user = profile[0].user_id;
delete profile[0].user_id;
res.send({'employmentInfo': profile[0]});
}
});
However I've tried not renaming it; I've also tried getting rid of my find override and just relying on the blueprint find method, neither of those worked either.
I am trying to expand the Meteor.users collection and I've got everything working fairly well so far except for some reason with this it's not allowing me to register new users anymore. I am using the accounts-google package for login/registration, logging in with an account that's already been created works great but when I attempt to register with a new account it doesn't work and I receive the following error in my browser console:
Exception in delivering result of invoking 'login': ReferenceError: ServiceConfiguration is not defined
at http://localhost:3000/packages/useraccounts_core.js?e3a764dbf634d8bf2a393797c0a82e9fadef2e7a:2551:48
at Accounts.callLoginMethod.userCallback (http://localhost:3000/packages/accounts-oauth.js?8a30b216f87b515ab9b4bf5d4970a7113d0c6c2f:163:7)
at http://localhost:3000/packages/accounts-base.js?7dabd814506e384c709f8bf707377955f9814129:612:26
at http://localhost:3000/packages/underscore.js?46eaedbdeb6e71c82af1b16f51c7da4127d6f285:794:19
at loggedInAndDataReadyCallback (http://localhost:3000/packages/accounts-base.js?7dabd814506e384c709f8bf707377955f9814129:708:7)
at null._callback (http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:999:22)
at _.extend._maybeInvokeCallback (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:3500:12)
at _.extend.receiveResult (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:3520:10)
at _.extend._livedata_result (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:4625:9)
at onMessage (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:3365:12)
Can anyone see where I went wrong here? I've been playing around with it for quite a while and just cant seem to get it to work. Any help/insight is greatly appreciated.
Schema = {};
Schema.UserProfile = new SimpleSchema({
userProfile: {
type: Object
},
'userProfile.firstName': {
type: String,
optional: true,
label: "First Name"
},
'userProfile.lastName': {
type: String,
optional: true,
label: "Last Name"
},
'userProfile.birthday': {
type: Date,
optional: true,
label: "Date of Birth"
},
'userProfile.contactEmail': {
type: String,
optional: true,
label: "Contact Email"
},
'userProfile.gender': {
type: String,
allowedValues: ['Male', 'Female'],
optional: true,
label: "Gender"
},
'userProfile.country': {
type: String,
optional: true,
label: "Country"
},
'userProfile.address': {
type: String,
optional: true,
label: "Address"
},
'userProfile.city': {
type: String,
optional: true,
label: "City"
},
'userProfile.stateProvince': {
type: String,
optional: true,
label: "State/Province"
},
'userProfile.postalCode': {
type: String,
optional: true,
label: "Postal Code"
},
'userProfile.phoneNumber': {
type: String,
optional: true,
label: "Phone Number"
},
});
Schema.User = new SimpleSchema({
username: {
type: String,
// For accounts-password, either emails or username is required, but not both. It is OK to make this
// optional here because the accounts-password package does its own validation.
// Third-party login packages may not require either. Adjust this schema as necessary for your usage.
optional: true
},
emails: {
type: Array,
// For accounts-password, either emails or username is required, but not both. It is OK to make this
// optional here because the accounts-password package does its own validation.
// Third-party login packages may not require either. Adjust this schema as necessary for your usage.
optional: true
},
"emails.$": {
type: Object
},
"emails.$.address": {
type: String,
regEx: SimpleSchema.RegEx.Email
},
"emails.$.verified": {
type: Boolean
},
createdAt: {
type: Date
},
profile: {
type: Schema.UserProfile,
optional: true
},
// Make sure this services field is in your schema if you're using any of the accounts packages
services: {
type: Object,
optional: true,
blackbox: true
},
// Add `roles` to your schema if you use the meteor-roles package.
// Option 1: Object type
// If you specify that type as Object, you must also specify the
// `Roles.GLOBAL_GROUP` group whenever you add a user to a role.
// Example:
// Roles.addUsersToRoles(userId, ["admin"], Roles.GLOBAL_GROUP);
// You can't mix and match adding with and without a group since
// you will fail validation in some cases.
roles: {
type: Object,
optional: true,
blackbox: true
},
// In order to avoid an 'Exception in setInterval callback' from Meteor
heartbeat: {
type: Date,
optional: true
}
});
Meteor.users.attachSchema(Schema.User);
Meteor.users.allow({
insert: function(userId, doc) {
// only allow posting if you are logged in
console.log("doc: " + doc + " userId: " + userId);
return !! userId;
},
update: function(userId, doc, fieldNames) {
// only allow updating if you are logged in
console.log("doc: " + doc + " userId: " + userId);
// a user can only update his own user doc and only the 'userProfile' field
return !! userId && userId === doc._id && _.isEmpty(_.difference(fieldNames, ['userProfile']));
},
});
Your standard 'new' user object does not match your schema and will fail on creation.
So, to get around this you want to reformat the output of the object provided by the Account.onCreateUser function:
Accounts.onCreateUser(function (options, user) {
//format the 'user' object as you need it to be here
// to pass your schema validation
return user;
})