Sequelize setter error 'invalid input syntax for integer: "[object Object]"' - node.js

I am trying to associate a list of contacts to a customer using the associations setter method, however, it always throws the error 'invalid input syntax for integer: "[object Object]"'.
The relevant query mentioned in the error is: UPDATE "contactperson" SET "refCustomerId"=$1,"updatedAt"=$2 WHERE "id" IN ('[object Object]')
This is how I use the setter:
db.customer.findByPk(customerID, {
include: [{
model: db.address,
as: 'address',
},{
model: db.contactoption,
as: 'contactOptions',
}, {
model: db.contactperson,
as: 'contactPersons',
}]
}).then(customer => {
customer.setContactPersons([ { firstName: 'tester', lastName: 'tester', description: 'lorem ipsum' } ]);
});
This is the association:
Customer.hasMany(models.contactperson, {
foreignKey: 'refCustomerId',
as: 'contactPersons'
});
Any idea what I'm doing wrong?

I managed to resolve this issue using the following code:
db.contactperson.bulkCreate([ { firstName: 'tester', lastName: 'tester', description: 'lorem ipsum' } ]).then(newContactPersons => {
customer.setContactPersons(newContactPersons);
});
It's a more complicated approach than intended, but it get's the job done.

You used set<ModelName>s that just updates a link field of given records. If you need to create contactperson record you need to use createContactPerson instead of setContactPersons (NOTE: you cannot create several records at once).
customer.createContactPerson({
firstName: 'tester',
lastName: 'tester',
description: 'lorem ipsum'
});
compare to:
const contactPerson = db.contactperson.findById(1);
if (contactPerson) {
customer.addContactPersons([contactPerson.id]);
}
set<ModelName>s - replaces old linked records with the new existing ones
add<ModelName>s - adds exisiting records in addition to old ones
create<ModelName> - create a new non-existing record in addition to old ones
See hasMany special methods

Exactly what Anatoly posted.
I had method declared on TypeScript like:
declare addPost: HasManyCreateAssociationMixin<PostClass, 'userId'>;
When i changed to:
declare createPost: HasManyCreateAssociationMixin<PostClass, 'userId'>;
Everything works so remember - how you describe name of method its very necesary.

Related

Use validation error values on custom Joi/celebrate messages

I'm creating something using a nodejs/typescript stack for the server, and I'm trying to define custom generic error messages instead of per-field messages. Something like this:
routes.post(
'/points',
upload.single('image'),
celebrate({
body: Joi.object().keys({
name: Joi.string().required(),
email: Joi.string().required().email(),
whatsapp: Joi.number().required(),
latitude: Joi.number().not(0).required(),
longitude: Joi.number().not(0).required(),
city: Joi.string().required(),
uf: Joi.string().required().max(2),
items: Joi.string().required()
}),
}, {
abortEarly: false,
messages: {
'string.empty':'{context.label} cant be empty!'
}
}),
pointsController.create
);
As you can see, I'm trying to use a variable/value inside the custom message. I got that 'key' based on the error entry that comes out of celebrate/joi error, which is like this:
{
message: ' cant be empty!',
path: [ 'items' ],
type: 'string.empty',
context: { label: 'items', value: '', key: 'items' }
}
If there a way to do something like that?
The message is not 'parsing' the {context.label} as I though it would. I mean, this is a shot in the dark since I couldn't find anywhere if something like this is suported at all.
You can use {#label} to achieve what you want to.
Try:
.messages({
'string.empty': '{#label} cant be empty!',
'any.required': '{#label} is a required field for this operation'
})
and so on for all other types.
Other values are also accessible similarly. For ex, if you want to generalise the error message for string min/max:
.messages({
'string.min': '{#label} should have a minimum length of {#limit}'
})
Here, limit (min) was set when you created the schema for the string.

match all if the user doesn't specify the field value MongoDB

I am building an API where I have several fields that are optional in my get request. So I want MongoDB to match all values for those optional fields if the user does not specify it. I have come up with this solution:
db.collection(expenses_collection).find(username: username, category: {$regex:"/" + category + "/"}, payment_type: {$regex:"/" + payment_type + "/"}})
Where if category and payment_type are not specified by the user I set them to ".*":
const {category=".*", payment_type=".*"} = req.query;
However, mongodb is still not matching any data. Any help is appreciated. Thanks a lot.
The issue is with your regex string. To match any string value, you have to use this pattern (this matches any string): (.*?)
Consider input documents:
{ _id: 1, name: "John", category: "cat 1", payment_type: "cash" },
{ _id: 2, name: "Jane", category: "cat 2", payment_type: "credit card" }
Usage to match any category field value:
let categoryStr = /(.*?)/
db.exp.find( { category: categoryStr } )
The query returns all documents.
So, in your application for the category value not specified the code can be like this:
if (category is empty or null) { // category not specified by user
categoryStr = /(.*?)/
}
Similarly, for the payment_type field also.
Then query would be:
db.exp.find( {
username: usernameStr,
category: categoryStr,
payment_type: paymentStr
} )
NOTE: The code tests fine with MongoDB NodeJS driver APIs.
Isn't this what exists is made for?
{category: { $exists: true }, payment_type: { $exists: true }}

GraphQL mutation that accepts an array of dynamic size in one request as input with NodeJs

I want to pass an object array of [{questionId1,value1},{questionId2,value2},{questionId3,value3}] of dynamic size in GraphQL Mutation with NodeJS
.........
args: {
input: {
type: new GraphQLNonNull(new GraphQLInputObjectType({
name: 'AssessmentStep3Input',
fields: {
questionId:{
name:'Question ID',
type: new GraphQLNonNull(GraphQLID)
},
value:{
name:'Question Value',
type: new GraphQLNonNull(GraphQLBoolean)
}
}
}))
}
},
.........
How can I do that with the given sample of code?
Thanks
If you want to pass an object array with GraphQL Mutation you need to use "GraphQLList" which allows you to pass an array with dynamic size of given input.
Here is the example
........
........
args: {
input: {
type: new GraphQLNonNull(GraphQLList(new GraphQLInputObjectType({
name: 'AssessmentStep3Input',
fields: {
questionId:{
name:'Question ID',
type: new GraphQLNonNull(GraphQLID)
},
value:{
name:'Question Value',
type: new GraphQLNonNull(GraphQLBoolean)
}
}
}))
)
}
},
........
........
Hope it helps.
Thanks
i just published the article on that, so that you can take a look if you would like to know more detail. This is the repository with the examples, where the createUsers mutation is implemented https://github.com/atherosai/express-graphql-demo/blob/feature/5-modifiers/server/graphql/users/userMutations.js. You can take a look how it is implemented, but in general the above answer is correct. You can input as many objects as you would like to in the array (if you have not implemented some number of items limiting, but it is not there by default).

mongoose updating a specific field in a nested document at a 3rd level

mongoose scheme:
var restsSchema = new Schema({
name: String,
menu: mongoose.Schema.Types.Mixed
});
simplfied document:
{
name: "Dominos Pizza",
menu:{
"1":{
id: 1,
name: "Plain Pizza",
soldCounter: 0
},
"2":{
id: 2,
name: "Pizza with vegetables",
soldCounter: 0
}
}
}
I'm trying to update the soldCounter when given a single/array of "menu items" (such as "1" or "2" objects in the above document) as followed:
function(course, rest){
rest.markModified("menu.1");
db.model('rests').update({_id: rest._id},{$inc: {"menu.1.soldCounter":1}});
}
once this will work i obviously will want to make it more generic, something like: (this syntax is not working but demonstrate my needs)
function(course, rest){
rest.markModified("menu." + course.id);
db.model('rests').update({_id: rest._id},{$inc:{"menu.+"course.id"+.soldCounter":1}});
}
any one can help with this one?
I looked for an answer but couldn't find nothing regarding the 3rd level.
UPDATE:
Added id to the ducument's subDocument
I think you want add all ids into sub-document, one way you can do as following.
Rest.find({_id: rest._id}, function(err, o) {
// add all ids into sub-document...
Object.keys(o.menu).forEach(function(key) {
o.menu[key].id = key;
});
o.save(function(err){ ... });
});
It seems you want to operate the key in query, I am afraid you cannot do it in this way.
Please refer to the following questions.
Mongodb - regex match of keys for subobjects
MongoDB Query Help - query on values of any key in a sub-object

How to get value form nested object in mongoose?

I have some code on nodejs using mongoose module, and I need to get nested value, let I show you:
I create Schema
var clientScheme = mongoose.Schema({
name: Object
address: String,
number: Number,
operator: Object,
services: Object,
email: String
})
Then I create model:
var Client = mongoose.model('Client', clientScheme);
Then goes creating/saving - it's easy, I just show you first client.json
{
"name":{
"first":"John",
"last":"Smith"
},
"address":"Avenue 1",
"number": 7012341,
"email":"john#gmail.com"
}
And then, I need to get this client by first name. I try to:
clients.find({"name":{"first":"John"}})
Doesn't work.
What's wrong?
You can do this with :
db.clients.find({"name.first":"John"})
You should use dotted notation:
Client.find({"name.first": "John"}, function(err, clients){
// your callback body here
});
It doesn't work because you try to find a record which has 'name' exactly like this:
{first: "John"}
but your client has name: {first: "John", last: "Smith"}
So, any of the following queries will find your client:
clients.find({"name.first": "John"}) or
clients.find({"name.last": "Smith"}) or
clients.find({"name": {first: "John", last: "Smith"}})
Hope it helps.

Resources