I want to recover my collection which is in the database.
The problem is that my query is still not defined.
Here is my request:
const products = {
getProducts: async (req, res) => {
const productId = req.query.id;
console.log(productId);
const product = await ProductsModel.find({}).exec();
if (product instanceof Error) {
res.status(500).json({ message: "Error" });
return;
}
res.json(product);
},
};
module.exports = products;
My schema with mongoose :
const ProductSchema = new mongoose.Schema({
image: {
type: String,
},
title: {
type: String,
},
description: {
type: String,
},
price: {
type: Number,
},
category: {
type: String,
},
});
const Products = mongoose.model("Products", ProductSchema);
module.exports = Products;
My Fetch :
const [products, setProducts] = useState([]);
useEffect(getProducts, []);
async function getProducts() {
const options = {
method: "GET",
}
const response = await fetch("http://localhost:8000/products", options);
const productsData = await response.json();
setProducts(productsData);
console.log(productsData);
}
My error message :
[nodemon] restarting due to changes...
[nodemon] starting node ./bin/www
(node:4279) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.
(Use node --trace-deprecation ... to show where the warning was created)
undefined
GET /products 304 14.493 ms - -
Thank you in advance for your help.
At first, while exporting from your Schema file you have done:
module.exports = Products;
But on your Request file while fetching product you have done:
const product = await ProductsModel.find({}).exec();
You should replaced it with:
const product = await Products.find({}).exec();
You are getting undefined on req.query because while request on server you have not passed query. To pass query use ?id=
In your Fetch File you should do following change:
const response = await fetch("http://localhost:8000/products?id="+productId, options);
Or, You can also use Tempelate Literals ``, this is a good practice.
const response = await fetch(`http://localhost:8000/products?id=${productId}`, options);
For deprecation warning, you have to do following changes where you have connect databse.
mongoose.connect('mongodb://localhost:27017/name',{
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex:true},()=>{console.log('database connected')}
Related
I'm learning to write apollo server by following a graphql tutorial https://www.howtographql.com/graphql-js/3-a-simple-mutation/ but when I try to write a delete mutation and use it in the GraphQL Playground, I get null after executing, and if I check data in the Prisma studio there is no change
mutation delete and server response
I'm sure that there are many items for deleting also with current id which I used for delete
this is my code
prisma studio data
const {ApolloServer} = require('apollo-server');
const fs = require('fs');
const path = require('path');
const { PrismaClient } = require('#prisma/client')
const prisma = new PrismaClient()
const resolvers = {
Query : {
info: () => 'Info text',
feed: async (parent, args, context, info) => {
return context.prisma.link.findMany()
},
},
Mutation : {
post: (parent, args, context, info) => {
const newLink = context.prisma.link.create({
data: {
url: args.url,
description: args.description,
},
})
return newLink
},
delete: (parent, args, context, info) => {
const deleteLink = context.prisma.link.delete({
data: {
id: args.id
}
})
return deleteLink
}
}
}
const server = new ApolloServer({
typeDefs: fs.readFileSync(
path.join(__dirname, 'schema.graphql'),
'utf8'
),
resolvers,
context: {
prisma,
}
})
server
.listen()
.then(({url})=>
console.log(`Server is running on ${url}`)
);
I gat it. Instead data use where. Prisma supports filtering with where query option.
async function deleteLink(parent, args, context, info){
const deleteLink = context.prisma.link.delete({
where: {
id: +args.id,
}
})
}
This is my backend controller, I am getting the rooms data
const allRooms = catchAsyncErrors(async (req, res) => {
const resPerPage = 4;
const roomsCount = await Room.countDocuments();
const apiFeatures = new APIFeatures(Room.find(), req.query)
.search()
.filter()
let rooms = await apiFeatures.query;
let filteredRoomsCount = rooms.length;
apiFeatures.pagination(resPerPage)
rooms = await apiFeatures.query;
res.status(200).json({
success: true,
roomsCount,
resPerPage,
filteredRoomsCount,
rooms
})
})
This is my redux actions I am sending the payload and data
export const getRooms = (req, currentPage = 1, location = '', guests, category) => async (dispatch) => {
try {
const { origin } = absoluteUrl(req);
let link = `${origin}/api/rooms?page=${currentPage}&location=${location}`
if (guests) link = link.concat(`&guestCapacity=${guests}`)
if (category) link = link.concat(`&category=${category}`)
const { data } = await axios.get(link)
dispatch({
type: ALL_ROOMS_SUCCESS,
payload: data
})
} catch (error) {
dispatch({
type: ALL_ROOMS_FAIL,
payload: error.response.data.message
})
}
}
This is my reducer function, dispatching the room data
export const allRoomsReducer = (state = { rooms: [] }, action) => {
switch (action.type) {
case ALL_ROOMS_SUCCESS:
return {
rooms: action.payload.rooms
}
case ALL_ROOMS_FAIL:
return {
error: action.payload
}
case CLEAR_ERRORS:
return {
...state,
error: null
}
default:
return state
}
}
Here I want to get the data using wrapper.getStaticProps but I am getting an error, but when i am using wrapper.getServerSideProps I get the data.
export const getStaticProps = wrapper.getStaticProps(store=> async ({ req, query, }) => {
await store.dispatch(getRooms(req, query.page, query.location, query.guests, query.category))
})
It seems that in ({ req, query, }) => , query is undefined.
Going by the documentation of next, the context object for getStaticProps has no property query. It is only available in getServerSideProps.
See also this info:
Only runs at build time
Because getStaticProps runs at build time, it does not receive data that’s only available during request time, such as query parameters or HTTP headers as it generates static HTML.
I'm trying to deploy an app using Prismic as CMS and everything works perfectly locally, but once I deploy to vercel I get the error:
19:09:51.850 | TypeError: Cannot read property 'titulo_categoria' of undefined
There seems to be something wrong when it tries to get the data from Prismic.
My code is the following:
import {getAllCategorias, getCategory2} from '../../lib/api';
export default function Index({cat}) {
return <>{cat.titulo_categoria[0].text}</>;
}
export async function getStaticProps({params}) {
const data = await getCategory2(params.slug);
return {
props: {
cat: data?.categorias ?? null,
},
};
}
export async function getStaticPaths() {
const allPosts = await getAllCategorias();
return {
paths: allPosts?.map(({node}) => `/test/${node._meta.uid}`) || [],
fallback: true,
};
}
And the API code that gets data from Prismic is:
import Prismic from 'prismic-javascript';
const REPOSITORY = process.env.PRISMIC_REPOSITORY_NAME;
const REF_API_URL = `https://${REPOSITORY}.prismic.io/api/v2`;
const GRAPHQL_API_URL = `https://${REPOSITORY}.prismic.io/graphql`;
// export const API_URL = 'https://your-repo-name.cdn.prismic.io/api/v2'
export const API_TOKEN = process.env.PRISMIC_API_TOKEN;
export const API_LOCALE = process.env.PRISMIC_REPOSITORY_LOCALE;
export const PrismicClient = Prismic.client(REF_API_URL, {
accessToken: API_TOKEN,
});
async function fetchAPI(query, {previewData, variables} = {}) {
const prismicAPI = await PrismicClient.getApi();
const res = await fetch(
`${GRAPHQL_API_URL}?query=${query}&variables=${JSON.stringify(variables)}`,
{
headers: {
'Prismic-Ref': previewData?.ref || prismicAPI.masterRef.ref,
'Content-Type': 'application/json',
'Accept-Language': API_LOCALE,
Authorization: `Token ${API_TOKEN}`,
},
}
);
if (res.status !== 200) {
console.log(await res.text());
throw new Error('Failed to fetch API');
}
const json = await res.json();
if (json.errors) {
console.error(json.errors);
throw new Error('Failed to fetch API');
}
return json.data;
}
export async function getCategory2(slug) {
const data = await fetchAPI(
`
query CategoryBySlug($slug: String!, $lang: String!) {
categorias(uid: $slug, lang: $lang) {
titulo_categoria
_meta {
uid
}
}
}
`,
{
variables: {
slug,
lang: API_LOCALE,
},
}
);
return data;
}
Any idea what's wrong with this? I been trying to figure it out for the whole day without any luck
Perhaps you already checked that, but since you mentioned everything works locally and not on Vercel are you sure your environment variables are set there? Especially PRISMIC_API_TOKEN since it appears you're relying on it to query the API?
Also I'm a bit worried about that part of the code:
props: {
cat: data?.categorias ?? null,
}
...where you might be sending a null value to your Index component resulting in your error, I'd try that instead:
props: {
cat: data?.categorias ?? {},
}
...plus using the safe navigation operator (?.) on the Index component?
Let me know how it goes!
I've written a cloud task and it works perfectly and triggers the link I gave without any problems, but it won't stop retrying running the link.
How can I make it run it only once?
What I'm trying to do is run a Firestore Function once in the future, on a document write in a collection. I found this tutorial for it.
So far my task creation code works perfectly, and delivers correct payload to the function it's going to call. And the called function works correctly too the first time it runs and exits with status 200. But on the retries I have to exit with error 500 since there's no data to access anymore.
I can see the 200 and 500 logs in firestore function's logs, but Cloud Tasks' logs is empty, even if a method has been run 50 times!
This is the full code
import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'
const { CloudTasksClient } = require('#google-cloud/tasks')
exports.moveActivityFromPlanToRecord = () =>
functions
.region('europe-west1')
.firestore.document('Users/{userId}/Activities/{activityId}')
.onCreate(async snapshot => {
const moveTime = snapshot.data()! as MoveTime
if (!moveTime || !moveTime.dueTime) {
console.log("DueTime is empty or null: \n" + moveTime)
return
}
// Get the project ID from the FIREBASE_CONFIG env var
const project = JSON.parse(process.env.FIREBASE_CONFIG!).projectId
const location = 'europe-west1'
const queue = 'activityDateEventChecker'
//queuePath is going to be a string that uniquely identifes the task
const tasksClient = new CloudTasksClient()
const queuePath: string =
tasksClient.queuePath(project, location, queue)
// URL to my callback function and the contents of the payload to deliver
const url = `https://${location}-${project}.cloudfunctions.net/activityDateEventCheckerCallback`
const docPath = snapshot.ref.path
const dueTime = moveTime.dueTime
const payload: MoveTaskPayload = { docPath, dueTime }
console.log(payload)
// build up the configuration for the Cloud Task
const task = {
httpRequest: {
httpMethod: 'POST',
url: url,
body: Buffer.from(JSON.stringify(payload)).toString('base64'),
headers: {
'Content-Type': 'application/json',
},
},
scheduleTime: {
seconds: moveTime.dueTime / 1000
}
}
// enqueue the task in the queue
return tasksClient.createTask({ parent: queuePath, task: task })
})
interface MoveTime extends admin.firestore.DocumentData {
dueTime?: number
}
interface MoveTaskPayload {
docPath: string,
dueTime: number
}
exports.activityDateEventCheckerCallback = () =>
functions
.region('europe-west1')
.https.onRequest(async (req, res) => {
const payload = req.body as MoveTaskPayload
try {
// getting the item
const activity = await admin.firestore().doc(payload.docPath).get()
// if time is up for it
if (Date.now() >= payload.dueTime && activity.data() != undefined) {
// getting path to activity to be in record
const pathUser = activity.ref.parent.parent?.path
const pathDocRecord = admin.firestore().doc(`${pathUser}/Record/${activity.id}`)
console.log("RECORD-- ", (await (await pathDocRecord.get()).data())?.subject)
// moving activity into record
await pathDocRecord.set(activity.data()!)
await activity.ref.delete()
// sending notif to user
const fcmPayload = {
notification: {
title: `${activity.data()?.subject}`,
body: " Time for activity. Record how it goes!"
},
data: {
activityId: activity.id
}
}
const user = await admin.firestore().doc(pathUser!).get()
const fcmToken: string = user.data()?.fcmToken
return admin.messaging().sendToDevice(fcmToken, fcmPayload)
}
return null
} catch (error) {
console.error(error)
res.status(500).send(error)
return null
}
})
Tasks in Cloud Task retries when it does not get response code 2XX.
You can config the retry in Cloud Task Queue using maxAttempt paramtere.
Details are mentioned in the doc
My nodejs app calls nexmo API to send SMS message. Here is the API:
nexmo.message.sendSms(sender, recipient, message, options, callback);
In the app, it is
const nexmo = new Nexmo({
apiKey: "nexmoApiKey",
apiSecret: "nexmoSecret"
}, { debug: true });
nexmo.message.sendSms(nexmo_sender_number, cell_country + to, message, {type: 'unicode'}, async (err, result) => {....});
Is there a way I can convert it to async/await structure like below:
const {err, result} = nexmo.message.sendSms(nexmo_sender_number, cell_country + to, vcode, {type: 'unicode'});
if (err) {.....};
//then process result...
I would like to return the message to parent function after the message was successfully sent out.
The nexmo-node library only supports callbacks for now. You'll need to use something like promisify or bluebird to convert the sendSms function to promises, and the use async/await with it. Here is an example using Node's promisify
const util = require('util');
const Nexmo = require('nexmo');
const nexmo = new Nexmo({
apiKey: "nexmoApiKey",
apiSecret: "nexmoSecret"
}, { debug: true });
const sendSms = util.promisify(nexmo.message.sendSms);
async function sendingSms() {
const {err, result} = await sendSms(nexmo_sender_number, cell_country + to, message, {type: 'unicode'});
if (err) {...} else {
// do something with result
}
}
Though Alex's solution is elegant. It breaks TypeScript and util does some 'hidden logic' on the promises; when it errors stack traces are not clear.
This also allows you to stay true to the API and get auto-fill on the properties.
So instead you can do this (TypeScript)
/**
* Return the verification id needed.
*/
export const sendSMSCode = async (phoneNumber: string): Promise<string> => {
const result = await new Promise(async (resolve: (value: RequestResponse) => void, reject: (value: VerifyError) => void) => {
await nexmo.verify.request({
number: phoneNumber,
brand: `${Config.productName}`,
code_length: 4
}, (err, result) => {
console.log(err ? err : result)
if (err) {
reject(err)
}
resolve(result)
});
})
return result.request_id
}