I want to delete all items (aka records/rows) in a DynamoDB table. I understand that the documentation advises to simply drop the whole table and re-create it, but I've created my table with AWS Amplify and I don't want to risk breaking the rest of my stack.
I've had a look at the DynamoDB API and the aws-sdk (I'm using javascript). I can delete single items in the database but I'm struggling to expand that to deleting multiple items.
// Delete single item:
import { DeleteItemCommand } from "#aws-sdk/client-dynamodb";
import { ddbClient } from "./dynamoDbClient";
const tableName = "myTableName";
const itemId = "12f10644-546c-45f4-8309-c208061e9737";
export async function deleteItemDynamoDb() {
const command = new DeleteItemCommand({
TableName: tableName,
Key: {
id: {
S: "12f10644-546c-45f4-8309-c208061e9737",
},
},
});
const response = await ddbClient.send(command);
}
I can't figure out how to use the BatchGetItemCommand to get all/many records from a table, so I have fudged a solution by combining AppSync and DynamoDB:
export async function listCardsIncDeleted(): Promise<Card[]> {
const getCardQueryString = `query listCards {
listCards(limit:500) {
items {
id
name
_deleted
_version
status
}
}
}`;
try {
const response = (await appSyncClient.query({
query: gql(getCardQueryString),
fetchPolicy: "network-only",
})) as {
data: { listCards: { items: Card[]; __typename: "ModelCardConnection" } };
};
const { items } = response.data.listCards;
console.log({ items });
return items;
} catch (error) {
console.log(error);
throw new Error("ERROR");
}
}
async function deleteAllTimes(arrayOfCardObjects: { id: string }[]) {
let count = 0;
for await (const curCard of arrayOfCardObjects) {
await new Promise((resolve) => setTimeout(resolve, 50));
const deleteResponse = await deleteById(curCard.id);
count++;
console.log({ deleteResponse, curCardId: curCard.id, count });
}
return count;
}
async function listAppSyncThenDelete() {
const listOfCards = await listCardsIncDeleted();
const deletedAll = deleteAllTimes(listOfCards);
return deletedAll;
}
Hello guys I have the following problem:
wherever I try to post a comment I get the following error:
ClientError: input:3: Field "post" is not defined by type CommentCreateInput.
: {"response":{"errors":[{"message":"input:3: Field \"post\" is not defined by type CommentCreateInput.\n"}],"data":null,"extensions":{"requestId":"cl3uwxntaa8r70cll4db25q72"},"status":400,"headers":{}},"request":{"query":"\n mutation CreateComment($name: String!, $email: String!, $comment: String!, $slug: String!) {\n createComment(data: {name: $name, email: $email, comment: $comment, post: {connect: {slug: $slug}}}) { id }\n }\n ","variables":{"name":"Roberto","email":"robert.rivera#outlook.com","comment":"a","slug":"react-testing"}}}
at /home/xue/Documents/Programacion/blog-nodejs/node_modules/graphql-request/dist/index.js:356:31
at step (/home/xue/Documents/Programacion/blog-nodejs/node_modules/graphql-request/dist/index.js:63:23)
at Object.next (/home/xue/Documents/Programacion/blog-nodejs/node_modules/graphql-request/dist/index.js:44:53)
at fulfilled (/home/xue/Documents/Programacion/blog-nodejs/node_modules/graphql-request/dist/index.js:35:58)
at processTicksAndRejections (internal/process/task_queues.js:97:5) {
response: {
}
API resolved without sending a response for /api/comments, this may result in stalled requests.
this is my code so far:
pages/api/comments.js
import { GraphQLClient, gql } from 'graphql-request';
const graphqlAPI = process.env.NEXT_PUBLIC_GRAPHCMS_ENDPOINT
const graphcmsToken = process.env.XUE_TOKEN
// export a default function for API route to work
export default async function asynchandler(req, res) {
console.log({graphcmsToken})
const graphQLClient = new GraphQLClient((graphqlAPI), {
headers: {
authorization: `Bearer ${graphcmsToken}`,
},
})
const query = gql`
mutation CreateComment($name: String!, $email: String!, $comment: String!, $slug: String!) {
createComment(data: {name: $name, email: $email, comment: $comment, post: {connect: {slug: $slug}}}) { id }
}
`
try {
const result = await graphQLClient.request(query, req.body)
return res.status(200).send(result)
} catch (error) {
console.log(error)
}
}
-- this my commentform.jsx
components/commentForm.jsx
import React, { useState, useEffect } from 'react';
import { submitComment } from '../services';
const CommentsForm = ({ slug }) => {
const [error, setError] = useState(false);
const [localStorage, setLocalStorage] = useState(null);
const [showSuccessMessage, setShowSuccessMessage] = useState(false);
const [formData, setFormData] = useState({ name: null, email: null, comment: null, storeData: false });
useEffect(() => {
setLocalStorage(window.localStorage);
const initalFormData = {
name: window.localStorage.getItem('name'),
email: window.localStorage.getItem('email'),
storeData: window.localStorage.getItem('name') || window.localStorage.getItem('email'),
};
setFormData(initalFormData);
}, []);
const onInputChange = (e) => {
const { target } = e;
if (target.type === 'checkbox') {
setFormData((prevState) => ({
...prevState,
[target.name]: target.checked,
}));
} else {
setFormData((prevState) => ({
...prevState,
[target.name]: target.value,
}));
}
};
const handlePostSubmission = () => {
setError(false);
const { name, email, comment, storeData } = formData;
if (!name || !email || !comment) {
setError(true);
return;
}
const commentObj = {
name,
email,
comment,
slug,
};
if (storeData) {
window.localStorage.setItem('name', name);
window.localStorage.setItem('email', email);
} else {
window.localStorage.removeItem('name');
window.localStorage.removeItem('email');
}
submitComment(commentObj)
.then((res) => {
if (res.createComment) {
if (!storeData) {
formData.name = '';
formData.email = '';
}
formData.comment = '';
setFormData((prevState) => ({
...prevState,
...formData,
}));
setShowSuccessMessage(true);
setTimeout(() => {
setShowSuccessMessage(false);
}, 3000);
}
});
};
return (
);
};
export default CommentsForm;
I don't know how to get this working and sorry for my bad english. Let me know if you need more info
edit:
this is my schema I don't know if im missing something
import { request, gql } from 'graphql-request';
const graphqlAPI = process.env.NEXT_PUBLIC_GRAPHCMS_ENDPOINT;
export const getPosts = async () => {
const query = gql`
query MyQuery {
postsConnection {
edges {
cursor
node {
author {
bio
name
id
photo {
url
}
}
createdAt
slug
title
excerpt
featuredImage {
url
}
categories {
name
slug
}
}
}
}
}
`;
const result = await request(graphqlAPI, query);
return result.postsConnection.edges;
}
export const getRecentPosts = async () => {
const query = gql`
query getPostDetails() {
posts(
orderBy: createdAt_ASC
last: 3
) {
title
featuredImage {
url
}
createdAt
slug
}
}
`;
const result = await request(graphqlAPI, query);
return result.posts;
}
export const getSimilarPosts = async ( categories, slug ) => {
const query = gql`
query GetPostDetails($slug: String!, $categories: [String!]) {
posts(
where: { slug_not: $slug, AND: { categories_some: {slug_in: $categories} } }
last: 3
) {
title
featuredImage {
url
}
createdAt
slug
}
}
`
const result = await request(graphqlAPI, query, { categories, slug });
return result.posts
}
export const getCategories = async () => {
const query = gql`
query GetCategories {
categories {
name
slug
}
}
`
const result = await request(graphqlAPI, query)
return result.categories
}
export const getPostDetails = async (slug) => {
const query = gql`
query GetPostDetails($slug : String!) {
post(where: {slug: $slug}) {
title
excerpt
featuredImage {
url
}
author{
name
bio
photo {
url
}
}
createdAt
slug
content {
raw
}
categories {
name
slug
}
}
}
`;
const result = await request(graphqlAPI, query, { slug })
return result.post
}
export const submitComment = async (obj) => {
const result = await fetch('/api/comments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(obj),
})
return result.json()
}
I assume you are using graphcms. Go to the graphcms dashboard and set up a relationship between the Post and Comment identities.
If you check well in the Schema>Post section at the end there should be a relationship with the comment entity.
graphCMS is complaining that you are trying to assign a comment to a post; when the "Post" entity has no reference to "Comment"
The Relation in graphCMS is called a Reference. From the "Post" entity assign a reference to "Comment"
I have a graphql query and a working useState.
How can I manage my 'title' useState with it? I'd like that the title would be in the query instead of "Bad boys" to send.
function Home() {
const [title, setTitle] = useState("");
const searchMovies = async (e) => {
e.preventDefault();
console.log("submitting");
const query = `{
searchMovies(query: "Bad boys") {
id
name
overview
releaseDate
cast {
id
person {
name
}
role {
... on Cast {
character
}
}
}
}
}`;
const url = "https://tmdb.sandbox.zoosh.ie/dev/graphql";
try {
request("https://tmdb.sandbox.zoosh.ie/dev/graphql", query).then((data) =>
console.log(data)
);
} catch (err) {
console.log(err);
}
};
The query is an interpolated string so you can pass variables into it like this:
const query = `{
searchMovies(query: ${title}) {
id
name
overview
releaseDate
cast {
id
person {
name
}
role {
... on Cast {
character
}
}
}
}
}`;
I have a page with a list of objects called stories that displays all my stories in an array. I also have a detail page with displays an individual story.
I want to click on a link on any given story on the list, then it will navigate me to the individual story. I want to use _id as my dynamic part of the URL, as shown in the GraphQL below.
My Graphql
export const listAllStories = () => {
const query = gql`
query StoryEntries($size: Int) {
storyEntries(_size: $size) {
data {
_id
_ts
name
premises{
data{
_id
content
}
}
createdAt
}
}
}
`
return graphQLClient
.request(query, { size: 999 })
.then(({ storyEntries: { data } }) => data)
}
IN MY PAGES API I HAVE
export default async function handler(req, res) {
const handlers = {
GET: async () => {
const storyEntries = await listAllStories()
res.json(storyEntries)
},
}
if (!handlers[req.method]) {
return res.status(405).end()
}
await handlers[req.method]()
}
ON THE STORY LIST PAGE I HAVE
const ENTRIES_PATH = '/api/entries/allStories'
const useEntriesFlow = ({ initialEntries }) => {
const { data: entries } = useSWR(ENTRIES_PATH, {
initialData: initialEntries,
})
const EntryItem = ({ entry }) => (
<>
{entries?.map((entry) => (
{entry.name}
<Link href="/story/[storyId]" as={`/story/${entry._id}`}>
<a>Go</a>
</Link>
))}
</>
)
export const getStaticProps = async () => ({
props: {
initialEntries: await listAllStories(),
},
revalidate: 1,
})
This is fine and works.
**AND THEN ON THE DETAIL PAGE FOR EACH INDIVIDUAL STORY [storyId].js I HAVE **
export default function Story({story}) {
const router = useRouter()
const storyId = router.query.storyId
return(
<>
<h5>hello {story._id}</h5>
</>
)
}
export const getStaticPaths = async () => {
const res = await fetch(`${server}/api/entries/allStories/`);
const { data } = await res.json();
const paths = data.map(story => {
return {
params: { id: story._id.toString() }
}
// trying to get the _id from each story
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const { storyId } = context.query; // Your dynamic page is [storyId].js
const server = "http://localhost:3000";
const res = await fetch(`${server}/api/entries/allStories/${storyId}`);
// trying to get the params._id from each story
console.log(res)
const { data } = await res.json();
return {
props: { story: data }
}
}
ERROR
TypeError: Cannot read properties of undefined (reading 'map')
QUESTION
All I want to do is click on any story link, then it takes me to the details page, via the _id. I have tried a few things but I'm doing something (or some things) wrong.
Any help will be greatly appreciated.
EDIT AFTER. ERROR I'M GETTING. I'm not able to map my results on getStaticPaths
export const getStaticProps = async (context) => {
const { storyId } = context.query; // Your dynamic page is [storyId].js
const server = "YOUR SERVER VARIABLE";
const res = await fetch(`${server}/api/entries/allStories/${storyId}`);
// trying to get the params._id from each story
const { data } = await res.json();
return {
props: { story: data }
}
}
uncomment
const router = useRouter()
const storyId = router.query.storyId
// some helpful links
// https://nextjs.org/docs/basic-features/data-fetching#the-paths-key-required
// https://stackoverflow.com/questions/65783199/error-getstaticpaths-is-required-for-dynamic-ssg-pages-and-is-missing-for-xxx
export const getStaticPaths = async () => {
const server = "http://localhost:3000";
const data = await fetch(`${server}/api/entries/allStories/`).then(res => res.json() )
const paths = data.map(({_id}) => ({
params: { storyId: _id },
}))
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const storyId = context.params.storyId; // Your dynamic page is [storyId].js
const server = "http://localhost:3000";
// const res = await fetch(`${server}/api/entries/allStories/${storyId}`);
// trying to get the params._id from each story
// single api call (here)
const res = await fetch(`${server}/api/entries/allStories/`);
// removing const { data } because the data will be returned when calling res.json()
const data = await res.json();
// instead of the calling the single api (just a fix not recommended to access [0] directly )
return {
props: { story: data.filter(story => story._id === storyId)[0] }
}
}
I want to query my Supabase table using the ID in the slug e.g. localhost:3000/book/1 then show information about that book on the page in Next.js.
Table
book/[id].js
import { useRouter } from 'next/router'
import { getBook } from '#/utils/supabase-client';
export default function Book({bookJson}) {
const router = useRouter()
const { id } = router.query
return <div>
<p>Book: {id}</p>
<h1>{bookJson}</h1>
</div>
}
export async function getServerSideProps(query) {
const id = 1 // Get ID from slug
const book = await getBook(id);
const bookJson = JSON.stringify(book)
return {
props: {
bookJson
}
};
}
utils/supabase-client.js
export const getBook = async (id) => {
const bookString = id
let bookId = parseInt(bookString);
const { data, error } = await supabase
.from('books')
.select('id, name')
.eq('id', bookId)
if (error) {
console.log(error.message);
throw error;
}
return data || [];
};
As described in getServerSideProps documentation, you can access the route parameters through the getServerSideProps's context, using the params field.
params: If this page uses a dynamic route, params contains the route parameters. If the page name is [id].js, then params will look like { id: ... }.
export async function getServerSideProps(context) {
const id = context.params.id // Get ID from slug `/book/1`
// Rest of `getServerSideProps` code
}
Alternatively, you can also use the query field to access the route parameters. The difference is that query will also contain any query parameter passed in the URL.
export async function getServerSideProps(context) {
const id = context.query.id // Get ID from slug `/book/1`
// If routing to `/book/1?name=some-book`
console.log(context.query) // Outputs: `{ id: '1', name: 'some-book' }`
// ...
}