I'm using the sequelize 6. When I'm runing findOrCreate().spread it says "findOrCreate(...).spread is not a function". Here is my code:
const response = await Response.findOrCreate({
where: {
participantId,
questionId,
},
defaults: responseNewDetail,
})
return res.status(200).send({ status: 0, data: response })
This is working fine, but it does not seperate the created status and the model value.
When I'm trying to use spread:
Response.findOrCreate({
where: {
participantId,
questionId,
},
defaults: responseNewDetail,
}).spread(function(response,created){
return res.status(200).send({ status: 0, data: response })
})
It says "Response.findOrCreate(...).spread is not a function".
This is the model file(response.js):
const { Sequelize } = require("sequelize")
module.exports = (sequelize, DataTypes) =>
sequelize.define(
"Response",
{
responseId: {
type: DataTypes.INTEGER,
primaryKey: true,
allowNull: false,
field: "Response_ID",
autoIncrement: true,
},
companyId: {
type: DataTypes.INTEGER,
allowNull: false,
field: "Company_ID",
},
...
)
Response model:
const ResponseModel = require("../models/response")
const Response = ResponseModel(sequelize, DataTypes)
Does anyone know what's wrong?
Since you're using await, you can change:
const response = await Response.findOrCreate({
where: {
participantId,
questionId,
},
defaults: responseNewDetail,
})
return res.status(200).send({ status: 0, data: response })
to
const [ response, created ] = await Response.findOrCreate({
where: {
participantId,
questionId,
},
defaults: responseNewDetail,
})
return res.status(200).send({ status: 0, data: response })
and all will be well.
This doesn't address the spread not a function thing though. For that, I only noticed this when I upgraded sequelize from an older version (I've been using sequelize since version 1). Your example of spread really should be working but for whatever reason it does not anymore (it doesn't for me either). Typically the only time I'm using spread instead of just awaiting it is when I want to defer execution of something. Right or wrong, I've begun to tackle that by just wrapping the await/async version in:
setImmediate(async () => {
// async things here
});
Hope I helped, sorry if I didn't.
eleborating Brian's Answer :-
findOrCreate returns two values first model instance and second created status,
so you can use
const [model,created] = ModelName.findOrCreate();
(Model Response in your case)
to get created status.
Related
so I am trying to 'chain' togther multiple queries that are somewhat dependent on each other, using RTK Query and I'm not getting very far...
APIS
import { baseApi } from '#/lib/rtkQuery/baseApi';
export const personContactApi = baseApi
.enhanceEndpoints({ addTagTypes: ['mail_packs'] })
.injectEndpoints({
endpoints: (build) => ({
createList: build.mutation({
query: (body) => {
return {
url: `/person/list/`,
method: 'POST',
body,
};
},
}),
addPersonsToList: build.mutation({
query: ({ ListId, personArray }) => {
return {
url: `/person/list/${ListId}/add-persons/`,
method: 'POST',
body: { persons: personArray },
};
},
}),
sendList: build.mutation({
query: ({ ListId }) => {
return {
url: `/person/list/${ListId}/submit/`,
method: 'POST',
};
},
}),
}),
});
export const { useCreateListMutation, useAddpersonsToListMutation, useSendListMutation } =
personContactApi;
Query functions
const [createList, { data: listResponseObject, isSuccess: createListSuccess, isError: createListError }] = useCreateListMutation();
const [addPersonsToListMutation, { isSuccess: addPersonsToListSuccess, isError: addPersonsToListError }] = useAddPersonsToListMutation();
const [sendList, { isSuccess: sendListSuccess, isError: sendListError }] = useSendListMutation();
useEffect
useEffect(() => {
// When list successfully created, add persons to list
if (createListSuccess) {
addPersonsToListMutation({
ListId: listResponseObject?.id,
personsArray: selectedPersons,
});
}
}, [
addPersonsToListMutation,
createListSuccess,
listResponseObject,
selectedPersons,
]);
useEffect(() => {
// When persons have been successfully added to mailing list, send mailing list
if (addPersonsToListSuccess) {
sendList({
listId: listResponseObject?.id,
});
}
}, [
addPersonsToListSuccess,
listResponseObject,
sendList,
]);
These are the 3 queries / mutations and they need to go in order, once the create query is success we fire the add, once that is a success we fire the send
The add and send queries are also dependent on an id returned in the response from the createList query, and the add query required an array of ids representing the person objects being added to the list
I've hacked togther a solution using multiple useEffects but it is very brittle and obviously not the ideal way to handle this situation, any one have a better way I'm all ears.
One way of solving this would be to follow one of their official suggestions:
If you need to access the error or success payload immediately after a mutation, you can chain .unwrap().
In your example, the code would be something like this
createList(input_object_goes_here)
.unwrap()
.then(createListResponse => {
addPersonsToListMutation(createListResponse.values_you_need)
.unwrap()
.then(addPersonsResponse => sendList({ listId: addPersonsResponse.id }))
})
Hope I got the syntax right, but you should get the idea.
Source: https://redux-toolkit.js.org/rtk-query/usage/error-handling
I have a function on my server that is supposed to get a post by its ID. The function works up until the "foundPost" constant, where I can't seem to find one of the documents from the "posts" array. I've tried substituting findOne for find and the ObjectIds work for the const 'post'.
I've double checked that post_id is 62067c1211eea1531d5872f4
Here is the function to find a post:
const postById = async (req, res) => {
const userId = req.params.userId;
const post_id = req.params.post_id;
const posts = await Post.findOne({ user: userId });
console.log(posts); //see this below
const foundPost = await posts.findOne({ "upload": post_id }); //error here
console.log(foundPost);
return res.json({ success: true, Post: foundPost });
};
Here is what 'console.log(posts)' returns:
[
{
upload: new ObjectId("623b681bdf85df9086417723"),
edited: false,
title: 'Test 1',
description: 'testing post 1',
name: 'John ',
sharedPost: 0,
},
{
upload: new ObjectId("62067c1211eea1531d5872f4"),
edited: false,
title: 'Test 2',
description: 'testing post 2',
name: 'John ',
sharedPost: 0,
}
]
I'm hoping that the function will return:
{
success: true,
{
upload: new ObjectId("62067c1211eea1531d5872f4"),
edited: false,
title: 'Test 2',
description: 'testing post 2',
name: 'John ',
sharedPost: 0,
},
}
Can anyone see why the line const foundPost = await posts.findOne({ "upload": post_id }); isn't working?
Thank you for your help.
****** Response to answer ******
Hello, thanks a lot for your answer, unfortunately it's still giving an error. Please see below the model for the code I'm using:
const PostSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: "user",
},
post: [
{
user: {
type: Schema.Types.ObjectId,
ref: "user",
},
upload: {
type: Schema.Types.ObjectId,
ref: "upload",
},
title: {
type: String,
},
description: {
type: String,
},
},
],
date: {
type: Date,
default: Date.now,
},
});
I noticed that you used 'userProfile.posts' which I adapted to 'userProfile.post' to match this schema. I'm also not sure if you wanted to use 'subdoc' or 'subDoc' in line 11 of your code, but I tried both with the same error for each. I determined that the code stuck at the const subDocs = userPosts.filter(filter); line. I've looked into the .filter method you've used and can't find any potential errors. Not sure what the issue is.
Thanks
The issue is that you cannot run another mongo query on objects that were result of a previous query.
//will return a single document if found, or null if not found.
const posts = await Post.findOne({ user: userId });
//this will not work because at this point 'posts' will be either a Document or null value
//So the object will not have the method 'findOne' available.
const foundPost = await posts.findOne({ "upload": post_id });
The solution is to deal correctly with the types of objects you have.
Below is a functional and safe implementation that solves your issue:
const userPosts = await Post.findOne({ user: userId }).exec();
if (!userPosts) {
// document not found with provided userId
return res.json({ success: false });
}
//here we have a Document
//check if document has 'posts' property and is an array
if (userPosts.posts) {
//filter the posts array
const filter = function(subDoc) {
return subdoc.upload === post_id
}
const subDocs = userPosts.filter(filter);
//filter returns an array, so we must check if has itens
//then we grab the first item
if (subDocs.length > 0) {
const foundPost = subDocs[0];
return res.json({ success: true, Post: foundPost });
}
//subDoc not found, return correct response
return res.json({ success: false });
}
If your Post model schema is what I'm supposing to be, this code will work perfectly.
const schema = mongoose.schema({
user: Number,
posts: [{ upload: Number }]
})
In case of error, please add the code of the model schema structure.
This is my ToWatch Model in toWatch-model.js file which in code has UserModel->ToWatch 1:1 relationship and has ToWatch->MovieModel 1:M relationship.
const Sequelize = require('sequelize');
const sequelize = require('./../common/db-config');
const MovieModel = require ("./movie-model");
const UserModel = require("./user-model");
const Model = Sequelize.Model;
class ToWatch extends Model{}
ToWatch.init({
id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'id_towatch'
},
date: {
type: Sequelize.DATE,
allowNull: false,
field: 'date'
},
userId: {
type: Sequelize.INTEGER,
allowNull: false,
field: 'id_user',
references:{
model: UserModel,
key: "id"
}
},
movieId: {
type: Sequelize.INTEGER,
allowNull: false,
field: 'movie_id_towatch',
references:{
model: MovieModel,
key: "id"
}
},
},
{
sequelize,
modelName: 'towatch',
tableName: 'towatch',
timestamps: false
// options
});
//Here is the relation ************
UserModel.hasOne(ToWatch, {
foreignKey: {
type:Sequelize.DataTypes.INTEGER,
allowNull:false,
name:'fk_foreign_key_towatch'
}
});
ToWatch.belongsTo(UserModel);
ToWatch.hasMany(MovieModel, {
foreignKey: {
type:Sequelize.DataTypes.INTEGER,
allowNull:false,
name:'movie_id_towatch'
}
});
MovieModel.belongsTo(ToWatch);
module.exports = ToWatch;
I watched many tutorials, but being my first time trying to make a method that will return everything including something from my other table via ID, I wasn't sure where to put and how to put data that I need in this method, considering it has .then(data=>res.send). Tutorials were doing it other ways by fetching or using async-await, and even documentation didn't help me here. Can somebody tell me what to put and where inside this method, that is inside toWatch-controller.js file for me being able to see let's say all the movie data (title,img,date) ,as an array I think, of the getToWatch method.
const ToWatch = require('./../models/toWatch-model');
module.exports.getToWatch = (req,res) => {
ToWatch.findAll().then(toWatch => {
[WHAT DO I PUT HERE?]
res.send(toWatch);
}).catch(err => {
res.send({
status: -1,
error:err
})
})
}
I need something like this ToWatch{
color:red,
cinema:"MoviePlace",
movieId{title:"Anabel", img:"URL", date:1999.02.23}
As I understood your question right, what you trying to do is return toWatch model instances with including User and Movie models.
To do so you can pass options in findAll() method like below:
ToWatch.findAll({include: [{model: User}, {model: Movie}]})... //and rest of your code
Or alternatively to keep your code clean you can use scopes:
// below the toWatch-model.js file
ToWatch.addScope('userIncluded', {include: {model: User}})
ToWatch.addScope('movieIncluded', {include: {model: Movie}})
And in the getToWatch method:
// you can pass several scopes inside scopes method, its usefull when you want to combine query options
ToWatch.scopes('userIncluded', 'movieIncluded').findAll()... //rest of your code
For more information check out sequelize docs
I'm getting a warning:
Cache data may be lost when replacing the parts field of a Query object.
To address this problem (which is not a bug in Apollo Client), define a custom merge function for the Query.parts field, so InMemoryCache can safely merge these objects:
existing: [{"__ref":"Part:53"},{"__ref":"Part:55"},{"__ref":"Part:56"},{"__ref":"Part:57"},{"__ref":"Part:58"}]
incoming: [{"__ref":"Part:53"},{"__ref":"Part:55"},{"__ref":"Part:56"},{"__ref":"Part:57"}]
Now here is my Part type:
type Part {
id: ID!
created_at: DateTime!
updated_at: DateTime!
partName: String
partDescription: String
partQuantity: Long
usePercentage: Boolean
partPercentage: Float
type: String
published_at: DateTime
products(sort: String, limit: Int, start: Int, where: JSON): [Product]
partImage(sort: String, limit: Int, start: Int, where: JSON): [UploadFile]
stockevents(sort: String, limit: Int, start: Int, where: JSON): [Stockevent]
}
This warning triggers after I remove one part using mutation to delete a single part. Here it is:
const [partDelete] = useMutation(DELETE_PART, {
update(cache, { data }) {
const newData = Object.values(data)
const refresh = newData.map(name => name.part)
const refined = refresh.map(item => item.id)
cache.evict({
id: cache.identify({
id: refined.id
})
})
cache.writeQuery({
query: GET_PARTS
})
},
refetchQueries: [
{ query: GET_PARTS }
]
})
I am passing payload in a separate function and everything works but I keep getting this cache warning so I want to deal with it now.
I've went with updating InMemoryCache in my index.js but it still doesn't work:
export const client = new ApolloClient({
link,
cache: new InMemoryCache({
typePolicies: {
Part: {
merge(existing = [], incoming = []) {
return [...existing, ...incoming];
}
}
}
})
});
I've also tried to return only ...incoming but nothing different happens.
Thanks in advance, cheers!
The issue was in the structure of InMemoryCache config. After I changed it to this it worked:
export const client = new ApolloClient({
link,
cache: new InMemoryCache({
typePolicies: {
Query: {
Part: {
parts: {
fields: {
merge(existing, incoming) {
return incoming;
}
}
}
}
}
}
})
});
I have also removed update option from the mutation that includes evict and modify.
when you see this warning:
To address this problem (which is not a bug in Apollo Client), define a custom merge function for the Query.your_query_name field, so InMemoryCache can safely merge these objects:
try this for shorten:
const client = new ApolloClient({
uri: "your_API_link",
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
your_Query_Name: {
merge: (existing = [], incoming) => {
return incoming;
},
},
},
},
},
}),
});
So I have collections of Teacher, Classes. to understand my problem its necessary to understand my database. the structure is
const TeacherSchema = new Schema(
{
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
role: {
type: String,
default: "teacher"
},
userid: {
type: String,
required: true
},
password: {
type: String,
required: true
},
profileImage: {
type: String,
required: false
},
classes: [{
type:Schema.Types.ObjectId,
ref:'class'
}]//1 teacher will have multiple classes
},
{ timestamps: true }
);
and the class:
const ClassSchema = new Schema(
{
subject: {
type: String,
required: true
},
teacher:[{
type:Schema.Types.ObjectId,
ref: 'teacher'
}],//once class will have only one teacher
},
{ timestamps: true }
);
What i want to do is, I want to show teacher how many classes he/she has. here is my controller.
exports.getAllClass= async (req, res, next) => {
let teacherClasses
try{
teacherClasses= await Teacher.findById(req.params.id)//teacher database
arrayOfClass= teacherClasses.classes //getting the class it has array of objectID
arrayOfClass.forEach(async (classes)=>{
let classDB =await Class.findById(classes)
console.log(classDB.subject)// in the console it shows all the classes.
return res.status(200).json({
'name':classDB.subject //but here it only shows one class,the first class name
})
});
}catch(err){
console.log(err)
}
}
I have tried many thing, but cant reach to a proper solution. Can you tell me what did i do wrong here or is there any better approach? I want to show all the classes in the return. I am new in programming hence assigned in complex task, please help me.
You are using forEach on the arrayOfClass and within that forEach you return and send the response. So as soon as the first promise is resolved, the response is sent.
One simple way to do this is to use a for .. of loop and await each class-promise inside and keep track of each result. Once that's done you can send the response:
...
const classes = [];
for(const classId of arrayofClass) {
const classDB = await Class.findById(classId);
classes.push({ name: classDB.subject });
}
return res.json(classes);
Another way to do this is to use Promise.all() which might be better if you're dealing with a bigger dataset as is processes in parallel whereas the first solution processes in sequence:
...
const classPromises = await Promise.all(arrayofClass.map(classId => Class.findById(classId)));
const result = classPromises.map(classDB => ({
name: classDB.subject
}));
return res.json(result);