const Todo = mongoose.model("ToDo", {
text: String,
complete: Boolean
});
const yoga = createYoga({
schema: createSchema({
typeDefs: `
type Query {
todos: [Todo]
}
type Todo {
id: ID!
text: String!
complete: Boolean!
}
type Mutation {
createTodo(text: String!): Todo
updateTodo(id: ID!, complete: Boolean!): Boolean
removeTodo(id: ID!): Boolean
}
`,
resolvers: {
Query: {
todos: () => Todo.find()
},
Mutation: {
createTodo: async (_, { text }) => {
const todo = new Todo({ text, complete: false });
todo.save();
return todo;
},
updateTodo: async (_, { id, complete }) => {
Todo.findByIdAndUpdate(id, { complete });
return true;
},
removeTodo: async (_, { id }) => {
Todo.findByIdAndRemove(id);
return true;
}
}
},
}),
graphiql: {
title: 'To-Do Application',
defaultQuery: `{}`,
},
graphqlEndpoint: '/',
})
In GraphQL playground:
I can create a todo item.
I can query all items in my todo list
I cannot update or delete an item from the list. My query afterward returns my initial list.
"It looks like your post is mostly code; please add some more details. It looks like your post is mostly code; please add some more details"
Your problem is that the .save() function on a Mongoose model is async, so you have to await it
So add await in front of your todo.save(), Todo.findByIdAndUpdate() and todo.findByIdAndRemove()
Related
I'm working on a project with Next.js and Prisma. In one of my API routes, I have a three queries. The results of the first and second queries are used in the third query. I'd like to do all three operations as a transaction and then return the data from the first query in the response.
I'm familiar with using prisma.$transaction but I don't know how to write it in this case where results #1 and #2 are used by query #3. Here are the queries as they are written now. Thanks in advance!
const { boardId } = req.body
const { description, status, title } = req.body.task
const createTask = await prisma.task.create({
data: {
board: boardId,
description,
status,
title
}
})
const statusArray = await prisma.board.findUnique({
where: {
id: boardId
},
select: {
[status]: true
}
})
const updateBoardStatusArray = await prisma.board.update({
where: {
id: boardId
},
data: {
[status]: {
set: [...statusArray[status], createTask.id]
}
}
})
// return data from first query
res.status(201).json({task: createTask})
Here you go:
const { boardId } = req.body;
const { description, status, title } = req.body.task;
const [createTask] = await prisma.$transaction(async (prisma) => {
const createTask = await prisma.task.create({
data: {
board: boardId,
description,
status,
title,
},
});
const statusArray = await prisma.board.findUnique({
where: {
id: boardId,
},
select: {
[status]: true,
},
});
const updateBoardStatusArray = await prisma.board.update({
where: {
id: boardId,
},
data: {
[status]: {
set: [...statusArray[status], createTask.id],
},
},
});
return [createTask, statusArray, updateBoardStatusArray];
});
// return data from first query
res.status(201).json({ task: createTask });
You can learn more about Interactive Transaction here
i use redux toolkit with react native and mongodb (mongoose)
i delete item and it successfully deleted from db
but not in client and need to reload page
todoSlice :
import {createSlice} from '#reduxjs/toolkit';
export const todoSlice = createSlice({
name: 'todos',
initialState: {
todos: [],
pending: null,
error: null,
},
reducers: {
deleteTodo: (state, action) => {
return state
},
},
});
export const {deleteTodo} = todoSlice.actions;
export default todoSlice.reducer;
apiCall:
import axios from 'axios';
import {deleteTodo} from './todoSlice';
export const deleteOneTodo = async (id, dispatch) => {
try {
await axios.delete(`http://10.0.2.2:5000/todos/${id}`);
dispatch(deleteTodo());
} catch (err) {
console.log(err);
}
};
main :
const {todo} = useSelector(state => state);
const dispatch = useDispatch();
const {todos} = todo;
useEffect(() => {
getTodos(dispatch);
}, []);
const handleDelete = id => {
deleteOneTodo(id, dispatch);
};
you have to implement deleteTodo inside your todoSlice in order to remove the deleted id from your local state,
...
export const todoSlice = createSlice({
name: 'todos',
initialState: {
todos: [],
pending: null,
error: null,
},
reducers: {
deleteTodo: (state, action) => {
return state.filter((todo)=>todo.id!==action.payload.id);
},
},
});
...
and of course you have to pass the payload with the id of the todo you want to remove
export const deleteOneTodo = async (id, dispatch) => {
try {
await axios.delete(`http://10.0.2.2:5000/todos/${id}`);
dispatch(deleteTodo({id:id}));
} catch (err) {
console.log(err);
}
};
if you still have doubts you can follow this tutorial: https://www.youtube.com/watch?v=fiesH6WU63I
i just call 'getTodos' inside 'deleteOneTodo'
and delete 'deleteTodo' from reducer
i hope its a good practice
export const deleteOneTodo = async (id, dispatch) => {
try {
await axios.delete(`http://10.0.2.2:5000/todos/${id}`);
// i add this line =>
getTodos(dispatch);
} catch (err) {
console.log(err);
}
};
I have a mutation with input type but the response is Event validation failed, if try with the same mutation but with each argument input the mongoose validation is right.
This is with apollo 2 .
//Mutation fine
Mutation: {
createEvent: combineResolvers(
isAuthenticated,
async (parent, { text, description }, { models, me }) => {
const event = await models.Event.create({
text,description,
userId: me.id,
});
pubsub.publish(EVENTS.EVENT.CREATED, {
eventCreated: { event },
});
return event;
},
),
//Mutation with errors
createEventInput: combineResolvers(
isAuthenticated,
async (root, { input }, { models, me }) => {
const event = await models.Event.create(input,{
userId: me.id,
});
pubsub.publish(EVENTS.EVENT.CREATED, {
eventCreated: { event },
});
return event;
},
),
Error :
"errors": [ { "message": "Event validation failed: description: Path description is required., text: Path text is required.", "locations":
Graphql return Oject with null id.
with mongodb.
It looks strange to me.
If I delete new GraphQLNonNull() on MailType id,
It works with id: null, another fields working fine.
const MailType = new GraphQLObjectType({
name: 'Mail',
fields: () => ({
id: { type: new GraphQLNonNull(GraphQLID), },
...
})
const Query = {
mails: {
type: new GraphQLList(MailType),
args: {
senderId: { type: GraphQLID },
isOffline: { type: GraphQLBoolean },
},
async resolve(root, args, req, ctx) {
if (args.isOffline === false) {
let a = await model.aggregate([
{ $match: { isOffline: false } },
]);
let b = await model.find({ isOffline: false });
console.log(JSON.stringify(a) == JSON.Stringify(b)) /// return true
return a // error
return b // working
}
return model.find({senderId: args.senderId});
}
}
}
// with a
"errors": [
{
"message": "Cannot return null for non-nullable field Mail.id."
}]
I am in trouble for 2 hours but I do not get the answer.
Can anybody help me?
You probably have a mistake in your mongodb schema, not in graphQl.
make sure you did not define you id by id key, it should be _id.
for example if you are using mongoose it can be something like this:
const MailSchema = new Schema({
_id: {
type: String,
unique: true,
},
....
....
});
Maybe someone who has managed to pass this step is willing to provide some indications.
I have a schema, a resolver, i request the query and i have a null response.
Please can you help on topic?
module.exports = {
Query: {
allLinks: async (root, {filter}, {mongo: {Links, Users}}) => {
let query = filter ? {$or: buildFilters(filter)} : {};
return await Links.find(query).toArray();
}
and the query request looks like this:
query LinkListPageQuery {
allLinks {
...LinkList_allLinks
}
}
fragment LinkList_allLinks on LinkConnection {
edges {
cursor
...Link_link
}
}
fragment Link_link on LinkEdge {
node {
id
description
url
}
}
My schema looks like this:
const typeDefs = `
type Link implements Node {
id: ID!
url: String!
description: String!
postedBy: User
votes: [Vote!]!
}
interface Node {
id: ID!
}
type Query {
allLinks(filter: LinkFilter, first: Int): [LinkConnection]
node(
id: ID!
): Node
}
type LinkEdge {
node: Link!
cursor: String
}
type LinkConnection {
pageInfo: PageInfo
edges: LinkEdge
count: Int
}
input LinkFilter {
OR: [LinkFilter!]
description_contains: String
url_contains: String
}
}
`;
PS: This language schema is done according to graphql-tools package.
Resolver:
Query: {
users: async (root, { first, after }, { mongo: { Users }, user }) => {
const queryData = await Users.find(query).toArray();
first = first || queryData.length;
after = after ? parseInt(fromCursor(after), 10) : 0;
const edges = queryData.map((node, i) => ({
cursor: toCursor(i+1),
node: node._id,
})).slice(after, first + after);
const slicedUser = edges.map(({ node }) => node);
return {
edges,
pageInfo: {
startCursor: edges.length > 0 ? edges[0].cursor : null,
hasNextPage: first + after < queryData.length,
endCursor: edges.length > 0 ? edges[edges.length - 1].cursor : null
},
count: queryData.length,
};
},
UserConnection: {
edges: ({ edges }) => edges,
pageInfo: ({ pageInfo }) => pageInfo,
count: ({ count }) => count,
},
UserEdge: {
node: async ({ node },data, {dataloaders: {userLoader}}) => {
const user = await userLoader.load(node);
return user;
},
cursor: ({ cursor }) => cursor,
},