Sequelize throwing 'id must be unique' on create - node.js

new to Sequelize library. From my understanding, 'id' is created automatically by sequelize (and thats what I see in the database). However when I go to 'create' an object it will throw this error:
{ [SequelizeUniqueConstraintError: Validation error]
name: 'SequelizeUniqueConstraintError',
message: 'Validation error',
errors:
[ { message: 'id must be unique',
type: 'unique violation',
path: 'id',
value: '1' } ],
fields: { id: '1' } }
The offending code:
db.Account.create({
email: req.body.email,
password: req.body.password,
allowEmail: req.body.allowEmail,
provider: 'local',
role: 'user'
})
Notice ID is not specified anywhere, neither is it specified in my model definition. Also the query it generates runs fine if I run it in postgres admin:
INSERT INTO "Accounts" ("id","email","role","verifyCode","provider","cheaterScore","isBanned","allowEmail","updatedAt","createdAt") VALUES (DEFAULT,'cat69232#gmail.com','user','','local',0,false,false,'2016-01-27 04:31:54.350 +00:00','2016-01-27 04:31:54.350 +00:00') RETURNING *;
Any ideas to what I could be missing here?
edit:
postgres version: 9.5
stack trace starts here:
/node_modules/sequelize/lib/dialects/postgres/query.js:326

Postgres has a habit of not resetting the next number in the sequence (autoincrement field) after bulk inserts. So if you're doing any pre-filling of the data in an init routine or from a SQL dump file, that's probably your issue.
Check out this post https://dba.stackexchange.com/questions/65662/postgres-how-to-insert-row-with-autoincrement-id

Related

How to upload images to fastify + graphql backend with axios?

When sending images via axios I found I have to use formdata. I add my images here but when sending the formdata my entire backend just freezes, just says "pending".
Ive been following this
And my attempt so far:
backend:
Apollo:
import { ApolloServer, makeExecutableSchema } from 'apollo-server-fastify';
const schema = makeExecutableSchema({ typeDefs, resolvers });
const apolloServer = new ApolloServer({
schema,
uploads: {
maxFileSize: 10000000,
maxFiles: 5,
},
});
(async function() {
app.register(apolloServer.createHandler({ path: '/api' }));
})();
schema:
scalar DateTime
scalar Upload
input addUser {
Email: String!
Password: String
FirstName: String!
LastName: String!
Age: DateTime!
JobTitle: String!
File: Upload
}
type Mutation {
register(input: addUser!): Boolean
}
resolver:
Mutation: {
register: async (obj, args, context, info) => {
// how to get the formData?
},
}
FrontEnd:
I build the request like this:
const getMutation = (mutate: MutationNames, returParams?: any): any => {
const mutation = {
login: print(
gql`
mutation($email: String!, $password: String!) {
login(email: $email, password: $password) {
token
refreshToken
}
}
`
),
register: print(
gql`
mutation(
$firstName: String!
$email: String!
$lastName: String!
$age: DateTime!
$jobTitle: String!
$file: Upload
) {
register(
input: {
FirstName: $firstName
LastName: $lastName
Email: $email
Age: $age
JobTitle: $jobTitle
File: $file
}
)
}
`
),
}[mutate];
if (!mutation) return {};
return mutation;
};
In this case im using the register mutation.
I have a few hooks on how I handle the data fetching so Im not going to include it since it is alot of code. The data is fetched correctly in the front end and before posting to the backend im putting everything to a formData object:
const submitForm: SubmitForm = (obj: SendObject) => {
const Fdata = new FormData();
Fdata.append('0', fileImp.file);
Fdata.append('operations', JSON.stringify(obj.data));
const map = {
'0': ['variables.file'],
};
Fdata.append('map', JSON.stringify(map));
callAxiosFn(
{
method,
url: 'http://localhost:4000/api',
data: Fdata,
// headers: obj.headers,
},
qlType.toString()
);
};
gets called like this:
const response = await axios({
headers: {
Accept: 'application/json',
'x-token': localStorage.getItem('token'),
'x-refresh-token': localStorage.getItem('refreshToken'),
...(config.headers || {}),
},
...config,
});
config is AxiosRequestConfig
What Im sending:
I dont exactly understand How the formdata will hit my resolver endpoint and for that reason im doing something wrong since the backend returns:
(node:748) UnhandledPromiseRejectionWarning: [object Array] (node:748)
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This
error originated either by throwing inside of an async function
without a catch block, or by rejecting a promise which was not handled
with .catch(). (rejection id: 1) (node:748) [DEP0018]
DeprecationWarning: Unhandled promise rejections are deprecated. In
the future, promise rejections that are not handled will terminate the
Node.js process with a non-zero exit code.
I realize this is alot but Im at the end of my vits here, been at this the entire day. Any help is deeply appreciated.
EDIT:
Since my backend was questioned I thought I would just show that when sending data without appending Formdata like I do above then I get it working:
const submitForm: SubmitForm = (obj: SendObject) => {
callAxiosFn(
{
method,
url: 'http://localhost:4000/api',
data: obj.data,
},
qlType.toString()
);
};
obj.data is:
{query: "mutation ($firstName: String!, $email: String!, $l… Age: $age, JobTitle: $jobTitle, File: $file})↵}↵", variables: {…}}
query: "mutation ($firstName: String!, $email: String!, $lastName: String!, $age: DateTime!, $jobTitle: String!, $file: Upload) {↵ register(input: {FirstName: $firstName, LastName: $lastName, Email: $email, Age: $age, JobTitle: $jobTitle, File: $file})↵}↵"
variables:
age: "1977-04-04"
email: "JhoneDoe#hotmail.com"
file: File {name: "something.jpg", lastModified: 1589557760497, lastModifiedDate: Fri May 15 2020 17:49:20 GMT+0200 (centraleuropeisk sommartid), webkitRelativePath: "", size: 32355, …}
firstName: "Jhon"
jobTitle: "SomethingCool"
lastName: "Doe"
password: "CoolPassword!"123"
__proto__: Object
__proto__: Object
query getting sent in the browser:
Backend reciving the data but the image is not included:
EDIT:
Recently found that my fastify backend might have issues with reading formData.
tried installing
fastify-multipart
but got errors when registering it:
FST_ERR_CTP_ALREADY_PRESENT(contentType) ^ FastifyError
[FST_ERR_CTP_ALREADY_PRESENT]:
After that I tried:
npm uninstall fastify-file-upload
Error remained.
Well, I have not explored this topic yet. But I know that axios with GraphQL does not really work that well. Axios is made mainly for REST API calls. However, I really like and have learned a lot from this channel Ben Awad. The guy is really awesome and explains things clearly and nice. But the most important he is a GraphQL enthusiast and explores and presents various topic about it, as well with React.js, TypeORM & PostgreSQL. Here are some helpful links, from his channel, that might help with your issue:
Upload Files in GraphQL Using Apollo Upload
How to Upload a File to Apollo Server in React
I hope this helps! Please let me know if the content is helpful!
This took some time and usally when you take something for granted it takes time to find the mistake.
For anyone having the same problem please remember that the order you add something MATTERS!
What I did:
const Fdata = new FormData();
Fdata.append('0', fileImp.file); // NOTICE THIS
Fdata.append('operations', JSON.stringify(obj.data));
const map = { // NOTICE THIS
'0': ['variables.file'],
};
Fdata.append('map', JSON.stringify(map));
Problem:
Remember when I said order of appending things matter? Well the case here was that the mapping was added after the file was added.
The correct way:
const Fdata = new FormData();
Fdata.append('operations', JSON.stringify(obj.data));
const map = { // NOTICE THIS
'0': ['variables.file'],
};
Fdata.append('map', JSON.stringify(map));
Fdata.append('0', fileImp.file); // NOTICE THIS
Also note that in my qestion I missed setting the file itself to null in the variables:
variables: {
file: null,
},
This has to be done.
For more info read here
#CodingLittle glad you figured out the answer was related to the multipart form field ordering.
Some things to add (answering as I don't have the 50 reputation required to make a comment on your answer, despite being the graphql-upload author)…
Also note that in my qestion I missed setting the file itself to null in the variables
This is true, and good to get right, although in reality a lot of GraphQL multipart request spec server implementations will simply replace whatever is at the mapped path for a file with the upload scalar value without caring what was there — in theory, you could replace files in variables with asdf instead of null and it would still work. JSON.stringify would have replaced the file instances with something like {}.
A lot of your headaches could have been avoided if the backend responded with a clear 400 status and descriptive error message instead of throwing a gnarly UnhandledPromiseRejectionWarning error. If your graphql-upload dependency was up to date on the backend, you should have seen a descriptive error message when the requests were not conforming to the GraphQL multipart request spec regarding field ordering, as can be seen in the graphql-upload tests:
https://github.com/jaydenseric/graphql-upload/blob/v11.0.0/test/public/processRequest.test.js#L929
Try running npm ls graphql-upload in your backend project to check only one version is installed, and that it’s the latest published to npm (v11 at the time of this answer). Note that if you’re relying on Apollo Server to install it for you, they use a very out of date version (v8).

Display specific error message of Validation Error message with node js

How to display a specific error message from a Validation Error. I already display the error with this line of code return res.render("register", {error: err.message});
and show this error ValidationError: User validation failed: email: Email already exists
But it is showing my column field name 'email' and I don't wanna do that. Below is the whole error and I only want to display this message: 'Email already exists'
Ignore the location D: i removed my file directory
ValidationError: User validation failed: email: Email already exists
at ValidationError.inspect
errors:
{ email:
{ ValidatorError: Email already exists
at new ValidatorError (D:)
at validate (D:)
at D:
at process._tickCallback (internal/process/next_tick.js:68:7)
message: 'Email already exists',
name: 'ValidatorError',
properties: [Object],
kind: 'user defined',
path: 'email',
value: 'email#gmail.com',
reason: undefined,
[Symbol(mongoose:validatorError)]: true } },
_message: 'User validation failed',
name: 'ValidationError' }
To get a specific error message of Validation Error you can use mapped() function like below.
const errors = validationResult(req);
if (!errors.isEmpty()) {
console.log(errors.mapped().email.msg);
}
To access nested error message do this
err.errors.email.message
Simply create one temp variable and structure your message,
let err_msg = err.errors.email.message;
which will give: 'Email already exists'
You can leave user validation failed message, since same message may be repeated for all validations.

JHipster how to get yeoman prompt input without using props?

Suppose I have an array that contains an object in yeoman prompt:
const getDatabaseName = [
{
type: 'input',
name: 'dbName',
message: 'Please enter your database name:',
default: 'testdb',
store: true
}
]
I know we could use props.dbName to retrieve user input for this object. But, how would I get the input using standard object call?
I tried this: getDatabaseName[0].dbName, but it's undefined.

Mongoose unique validator does not behave like other validators

In my Users schema I have an email field defined as below:
...
email: {
unique: [true, 'A user with that email address exists. The email must be unique.'],
type: String,
lowercase: true,
required: [true, 'A user must have an email address']
},
...
When I leave the email empty while creating a user, I can see my cutomised error message defined in the schema required: [true, 'A user must have an email address']. However, if I pick an email address that is already used by another user, I get a different error, I cannot see my customised message defined in the unique field unique: [true, 'A user with that email address exists. The email must be unique.'].
Error when email is empty (what I find useful as getting the error message is easy): required notice that my error message A user must have an email address is shown.
Error create { MongooseError: User validation failed
at ValidationError (/Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongoose/lib/error/validation.js:23:11)
at model.Document.invalidate (/Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongoose/lib/document.js:1486:32)
at /Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongoose/lib/document.js:1362:17
at validate (/Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongoose/lib/schematype.js:705:7)
at /Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongoose/lib/schematype.js:742:9
at Array.forEach (native)
at SchemaString.SchemaType.doValidate (/Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongoose/lib/schematype.js:710:19)
at /Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongoose/lib/document.js:1360:9
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
errors:
{ email:
{ MongooseError: A user must have an email address
at ValidatorError (/Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongoose/lib/error/validator.js:24:11)
at validate (/Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongoose/lib/schematype.js:704:13)
at /Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongoose/lib/schematype.js:742:9
at Array.forEach (native)
at SchemaString.SchemaType.doValidate (/Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongoose/lib/schematype.js:710:19)
at /Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongoose/lib/document.js:1360:9
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
message: 'A user must have an email address',
name: 'ValidatorError',
properties: [Object],
kind: 'required',
path: 'email',
value: '' } },
message: 'User validation failed',
name: 'ValidationError' }
Error when email has already been used: unique
Error create { MongoError: E11000 duplicate key error collection: stellium-io.users index: email_1 dup key: { : "john#doe.com" }
at Function.MongoError.create (/Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongodb-core/lib/error.js:31:11)
at toError (/Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongodb/lib/utils.js:114:22)
at /Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongodb/lib/collection.js:657:23
at handleCallback (/Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongodb/lib/utils.js:95:56)
at /Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongodb/lib/bulk/unordered.js:465:9
at handleCallback (/Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongodb/lib/utils.js:95:56)
at resultHandler (/Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongodb/lib/bulk/unordered.js:413:5)
at /Users/fleavamini/Projects/stellium/stellium.io/node_modules/mongodb-core/lib/connection/pool.js:455:18
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
name: 'MongoError',
message: 'E11000 duplicate key error collection: stellium-io.users index: email_1 dup key: { : "john#doe.com" }',
driver: true,
code: 11000,
index: 0,
errmsg: 'E11000 duplicate key error collection: stellium-io.users index: email_1 dup key: { : "john#doe.com" }',
getOperation: [Function],
toJSON: [Function],
toString: [Function] }
Is this the intended behaviour? I want to be able to get my customised error in the unique field and return it to the user trying to create the new user object.
Uniqueness in Mongoose is not a validation parameter(like required),it tells Mongoose to create a unique index in MongoDB for that field.
The uniqueness constraint is handled entirely in the MongoDB server. When you add a document with a duplicate key, the MongoDB server will return the error that you are showing (E11000...).
You have to handle these errors yourself if you want to create custom error messages. The Mongoose documentation (search for "Error Handling Middleware") provides you with an example on how to create custom error handling:
schmea.post('save', function(error, doc, next) {
if (error.name === 'MongoError' && error.code === 11000) {
next(new Error('email must be unique'));
} else {
next(error);
}
});
or you can use this plugin mongoose-unique-validator
(although this doesn't provide you with the specific field for which the uniqueness constraint failed)
The uniqueness constraint is handled entirely in the MongoDB server. When you add a document with a duplicate key, the MongoDB server will return the error that you are showing (E11000...)
You have to handle these errors yourself if you want to create custom error messages.
like:
schmea.post('save',function(err,doc,next){
if (err.name === 'MongoError' && err.code === 11000) {
next(new Error('email must be unique'));
} else {
next(error);
}
});

Trying to receive value from Mongoose Database returns undefined?

I have been trying to get a password attribute from a Mongoose Database that I created to store users. I can get the username just fine, but when I try and use this to get the password:
User.find({ 'credentials.username': gusername }, function(err, user) {
if (err) throw err;
console.log(user);
console.log(user.credentials.password);
});
It logs this in the console:
Connected to the DB using Mongo!
GET /login 200 66.097 ms - 1931
GET /stylesheets/style.css 304 2.212 ms - -
drew
[ { credentials: { password: 'tueresputa99', username: 'drew' },
__v: 0,
_id: 569e5e99e7810411003c4c25 } ]
/home/ubuntu/workspace/routes/index.js:127
console.log(user.credentials.password);
^
TypeError: Cannot read property 'password' of undefined
at Query.<anonymous> (/home/ubuntu/workspace/routes/index.js:127:33)
at /home/ubuntu/workspace/node_modules/mongoose/node_modules/kareem/index.js:177 :19
at /home/ubuntu/workspace/node_modules/mongoose/node_modules/kareem/index.js:109:16
at doNTCallback0 (node.js:417:9)
at process._tickCallback (node.js:346:13)
[nodemon] app crashed - waiting for file changes before starting...
So as you can see, it successfully logs 'user', and you can see the password and username RIGHT there, but yet, I cannot get the password with user.credentials.password
Any help is appreciated! This is very frustrating :/
Your user inside of callback function is an array rather than an object. Notice JSON array square bracket before user object
-> [ <- { credentials:
If your purpose is to find exactly one user you should use User.findOne function.
See this: http://mongoosejs.com/docs/api.html#query_Query-findOne

Resources