How can I do multiple nested query using GraphQL Yoga?
This is my data
{
"user": [{
"id": 1,
"name": "Thomas",
"comment_id": [1, 2, 3]
},
{
"id": 2,
"name": "Riza",
"comment_id": [4, 5, 6]
}
],
"comment": [{
"id": 1,
"body": "comment 1"
},
{
"id": 2,
"body": "comment 2"
},
{
"id": 3,
"body": "comment 3"
}
]
}
The scenario is that I want to query a particular user with all its comments, but the user only stores the comment ids.
This is my code
const { GraphQLServer } = require('graphql-yoga');
const axios = require('axios');
const typeDefs = `
type Query {
user(id: Int!): User
comment(id: Int!): Comment
}
type User {
id: Int
name: String
comment: [Comment]
}
type Comment {
id: Int
body: String
}
`;
const resolvers = {
Query: {
user(parent, args) {
return axios
.get(`http://localhost:3000/user/${args.id}`)
.then(res => res.data)
.catch(err => console.log(err));
},
comment(parent, args) {
return axios
.get(`http://localhost:3000/comment/${args.id}`)
.then(res => res.data)
.catch(err => console.log(err));
},
},
User: {
comment: parent =>
axios
.get(`http://localhost:3000/comment/${parent.comment_id}`)
.then(res => res.data)
.catch(err => console.log(err)),
},
};
const server = new GraphQLServer({ typeDefs, resolvers });
server.start(() => console.log('Server is running on localhost:4000'));
Desired Query
{
user(id: 1) {
id
name
comment {
id
body
}
}
}
But it returns not found, because the endpoint that the axios hit is http://localhost:3000/comment/1,2,3'
How can i make it return all user's comments?
Thanks guys!
Assuming that comments API /comment/:id accepts only single id, you would need to make one API call per comment ID (unless there is an API which takes multiple ID's and return their data) and then return response from comment field resolver of User type.
This is how resolver for comment field would look like in that case:
User: {
comment: parent => {
let results = await Promise.all(parent.comment_id.map((id) => axios.get(`http://localhost:3000/comment/${id}`)))
return results.map((result) => result.data)
}
}
Apparently I also found this other solution
User: {
comment: parent =>
parent.comment_id.map(id =>
axios.get(`http://localhost:3000/comment/${id}`).then(res => res.data)
),
},
Performance wise, which one do you think it's better?
Related
i want to render an email of all the users for testing purpose, In fact i have done that using this method. --- {dataFromApi.map((item, i) => {item.email})} but still it didn't work
const [dataFromApi, setDataFromApi] = useState([]);
const URL = 'http://localhost:5000/users'
const requestOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
}
const submit = () => {
const data = fetch(URL, requestOptions);
data.then( (userdata) => {
return userdata.json();
}).then( (data) => {
setDataFromApi(data[0]);
}).catch( (err) => {
console.log(err);
})
}
return (
<div className="login">
<h1 className="loginTitle">Choose a Login Method</h1>
<p>{dataFromApi}</p>
<div className="wrapper">
.
.
.
.
.
here is the API response
[
{
"id": 1,
"email": "test1234#gm.com",
"password": null
},
{
"id": 2,
"email": null,
"password": null
},
{
"id": 3,
"email": "test#123.com",
"password": "12345678"
},
{
"id": 4,
"email": "test#231.com",
"password": "12345678"
},
{
"id": 5,
"email": "test#231.com",
"password": "12345678"
},
{
"id": 6,
"email": "test#231.com",
"password": "12345678"
},
{
"id": 7,
"email": "NEWtest#231.com",
"password": "123"
}
]
but getting this error
react_devtools_backend.js:4012 The above error occurred in the component:
and
react-dom.development.js:14887 Uncaught Error: Objects are not valid as a React child (found: object with keys {id, email, password}). If you meant to render a collection of children, use an array instead.
Like Adam said in the comments, you are trying to pack a collection of things into a tag meant for a single thing. You should iterate over the list rendering a thing for each item.
{dataFromApi.map((item, i) => <p key={i}>{item.email}</p>)}
I got the answer why i'm not getting the expected output because in this code
const submit = () => {
const data = fetch(URL, requestOptions);
data.then( (userdata) => {
return userdata.json();
}).then( (data) => {
setDataFromApi(data[0]); // this will store only one object into an array
}).catch( (err) => {
console.log(err);
})
}
here setDataFromApi(data[0]) will store only 1 object and to access the email from the object, we have to use only dataFromApi.email else dataFromApi will give only object which we can't render so that's why it is giving an error.
I have a model called order that has a property orderItem. orderItem is of type id orderItem here's an extract of the schema.
const mongoose = require('mongoose');
const orderSchema = mongoose.Schema({
orderItems: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'OrderItem',
required: true
}],
shippingAddress1: {
type: String,
required: true,
},
I create the order item first and then save the collection of order items as part of the new Order that I want to save. Done like this:
const orderItemsIds = Promise.all(req.body.orderItems.map(async orderItem => {
let newOrderItem = new OrderItem({
quantity: orderItem.quantity,
product: orderItem.product
})
newOrderItem = await newOrderItem.save();
return newOrderItem._id;
}))
try {
const resolvedOrderItemsIds = await orderItemsIds;
console.log(resolvedOrderItemsIds);
let order = new Order({
orderItems: resolvedOrderItemsIds,
...
})
// order = await order.save();
order.save(function (err) {
if(!order) {
return res.status(400).send('The order cannot be created!');
}
return res.status(201).send({'message': 'Order Created', order});
})
} catch (error) {
}
})
The OrderItems and Order are created and I get a response in PostMan that everything is created. I see results like this:
{
"message": "Order Created",
"order": {
"orderItems": [
"615562ab6c7cd7021c7e37f7",
"615562ab6c7cd7021c7e37f8"
],
"shippingAddress1": "21 sample street",
"shippingAddress2": "Sample Bus Stop",
"city": "Sample",
"zip": "100001",
"country": "Sample",
"status": "Pending",
"user": "6151a6d7f6d3b96060f0aec5",
"_id": "615562ab6c7cd7021c7e37fb",
"dateOrdered": "2021-09-30T07:09:31.493Z",
"id": "615562ab6c7cd7021c7e37fb"
}
}
What amuses me is that the Order does not get saved in MongoDB. Can I know what I am doing wrongly?
Turns out I was missing a required field when building the request body and there was no form of information about this after posting the request with the way I did it. I found out about my missing field when I saved the item like this:
await order.save().then(item => {
return res.status(201).send({'message': 'Order Created', item});
}).catch(err => {
res.status(400).send({"message": 'The order cannot be created!', "error": err});
})
I want to create a patch or put a function for edit values of the object array.
comments: [{
body: String,
date: Date,
id: String
}],
router.put('/comment/:id', (req, res) => {
const commentbody = req.body.body
Blog.findOneAndUpdate({ "_id": req.params.id }, { $set: { comments: { body: commentbody } } }).then(result => {
res.send('comment edited');
})
.catch(err => res.send(err))
})
I'm trying to create an api which will return search results which match more than one parameter. I can query one parameter fine at the moment.
Here is an example url
http://localhost:3000/api/search?term=javascript&impact=sdg1
I want the results to include both term=javascript AND impact=sdg1
import Cors from "cors";
import initMiddleware from "../../util/init-middleware";
import { connectToDatabase } from "../../util/mongodb";
const cors = initMiddleware(
Cors({
methods: ["GET", "POST", "OPTIONS"],
})
);
export default async function handler(req, res) {
await cors(req, res);
const { db } = await connectToDatabase();
const data = await db
.collection("jobs")
.aggregate([
{
$search: {
search: [
{
query: req.query.term,
path: ["title", "role"],
},
{
query: req.query.impact,
path: ["impact"],
},
],
},
},
])
.sort({ date: -1 })
.toArray();
res.json(data);
}
Is this possible and can anyone suggest the right sort of query to write?
Many thanks in advance
The way to accomplish this is with the compound operator. Here are the docs and here is how it would look in your code:
export default async function handler(req, res) {
await cors(req, res);
const { db } = await connectToDatabase();
const data = await db
.collection("jobs")
.aggregate([
{
$search: {
"compound": {
"must": [{
"text": {
"query": req.query.term,
"path": ["title", "role"],
}
}],
"filter":[{
"text": {
"query": req.query.impact,
"path": ["impact"],
}
}]
}
},
},
])
.sort({ date: -1 })
.toArray();
res.json(data);
}
I have problem with sending data via POST method in fetch(). So the problem is that from this >> body: JSON.stringify({ id: uuid(), name, password }) it sends couple of times almost the same data (i receive unique id, and diplicated name and password). In the othet words: with one form submission, I've got few objects with differnt id, and same name and password. Code:
const handleSubmit = e => {
e.preventDefault();
users.map(user =>
user.name !== name && name.length >= 3 && password.length >= 5
? fetch('http://localhost:3003/users', {
method: 'POST',
body: JSON.stringify({ id: uuid(), name, password }),
headers: {
'Content-Type': 'application/json'
}
})
.then(res => {
if (res.ok) {
return res.json();
}
throw new Error('Error');
})
.then(c => setUser([...users, c]))
.then(errorUserChange(false))
: errorUserChange(true)
);
};
db.json:
{
"users": [
{
"id": "c1a10ab0-24c7-11ea-af77-3b28fe4ea407",
"name": "cccccc",
"password": "cccccc"
},
{
"id": "cbf73890-24c7-11ea-af77-3b28fe4ea407",
"name": "kkkkkkk",
"password": "kkkkk"
},
{
"id": "cbf786b0-24c7-11ea-af77-3b28fe4ea407",
"name": "kkkkkkk",
"password": "kkkkk"
}
]
}
Of course I know that's not the best way to hold password, I'm just practicing json server and fetch().
Thanks for any help!