I’m working on a project where I have posts that are created and shown on a screen. I’ve done this using graphql subscriptions for real time updating of posts, but I need the user to also be able to delete their own posts and for that update to be shown in real time. The examples that I’ve found which are some what similar are old and use a different syntax, so I able to apply them to my project. Currently, I have:
import User from '../../models/User.js';
import Posts from '../../models/Posts.js';
import { requireAuth } from '../../services/auth.js';
import { PubSub } from 'graphql-subscriptions';
import { ObjectId } from "mongodb";
// need to change for product PubSub is not advised for production!!!
const pubsub = new PubSub();
const NEW_MESSAGE_EVENT = 'newMessage';
export default {
getPost: async (_, { offset, limit, topic },{user}) => {
try {
const post = await Posts
.find({"post.topic":topic})
.skip(offset)
.sort({"post.dateSent": -1 })
.limit(Math.min(limit, 100))
return post
} catch (error) {
throw error;
}
},
createPost: async (_, { input }) => {
try {
const post = new Posts(input);
await post.save();
pubsub.publish('NEW_POST_EVENT', { newPost: post });
return post;
} catch (error) {
throw error;
}
},
newPost: {
subscribe: () => pubsub.asyncIterator(['NEW_MESSAGE_EVENT'])
},
};
in my backend and:
...
export const GET_POST = gql`
query ($offset: Int!, $topic: String) {
getMessage(offset: $offset, limit: 20, topic: $topic) {
_id
sender {
senderId
}
post {
text
topic
dateSent
}
}
}
`;
export const CREATE_POST_MUTATION = gql`
mutation createPost($input: PostInput!) {
createPost(input: $input) {
post {
text
dateSent
}
}
}
`;
export const POST_SUBSCRIPTION = gql`
subscription {
_id
newPost {
sender {
senderId
}
post {
text
topic
dateSent
}
}
}
`;
export default function PostScreen() {
const [createPost,{ data: createPostDate, error:createPostError}] = useMutation(CREATE_POST_MUTATION)
async function createPostHandler (item: any) {
createPost({
variables: {
input: {
...
},
}})
}
const {data, loading, error, subscribeToMore, fetchMore: fetchMorePosts} = useQuery(GET_POST, {fetchPolicy: 'cache-and-network', variables: { offset: 0, topic: ''}})
useEffect(() => {
subscribeToMore({
document: POST_SUBSCRIPTION,
updateQuery: (prev, { subscriptionData }) => {
if (!subscriptionData) {
return prev;
}
const newPost = subscriptionData.data.newPost;
return {
getPost:[newPost, ...prev.getPost]
};
},
onError: err => console.error(err)
});
}, []);
const fetchMoreAndUpdateCache = useMemo(() => {
return async (offset: number) => {
await fetchMorePosts({
variables: { offset },
updateQuery: (prev, { fetchMoreResult }) => {
if (!fetchMoreResult) {
return prev;
}
const moreItems = fetchMoreResult.getPost;
if(moreItems.length < 1) {
setStopFetchMore(true);
}
return {
getPost: [...prev.getPost, ...moreItems]
};
}
});
};
}, []);
const fetchMore = useCallback(() => {
if(!data || loading || isStopFetchMore) {
return;
}
const offset = data.getPost.length;
if (offset >= 20) {
fetchMoreAndUpdateCache(offset);
}
}, [isStopFetchMore, loading, data]);
return (
...
)
}
in my frontend. I’ve thought of two ways of being able to delete and having it update with the subscription, but I’m not sure if either is the correct or most efficient way. The first way would be changing newPost
to updatePost
and have have something like:
deletePosts: async (_, { id}) => {
try {
console.log('id', ids)
const deletePost = await Posts.findOneAndDelete({_id:id}});
pubsub.publish('UPDATE_POST_EVENT', { updatePost: deletePost });
return deletePost;
} catch (error) {
throw error;
}
},
in the backend and try to check for changes in useEffect(() => {subscribeToMore({ document: POST_SUBSCRIPTION,...
in the frontend , where maybe I would have to filter out deletePost
from the getPost
query. The second way I thought this might be possible would be by having a whole separate subscription event: deletePost: { subscribe: () => pubsub.asyncIterator(['DELETE_POST_EVENT'])},
, but I’m not 100% sure on how I would use that to update the data in the frontend. I would really appreciate any help or advice on how to do this. Thank you!