ERROR in Read query using n AWS AppSync Chat Starter App written in Angular "Can't find field allMessageConnection" - aws-appsync

const message: Message = {
conversationId: conversationId,
content: this.message,
createdAt: id,
sender: this.senderId,
isSent: false,
id: id,
};
this.appsync.hc().then((client) => {
client
.mutate({
mutation: createMessage,
variables: message,
optimisticResponse: () => ({
createMessage: {
...message,
__typename: "Message",
},
}),
update: (proxy, { data: { createMessage: _message } }) => {
const options = {
query: getConversationMessages,
variables: {
conversationId: conversationId,
first: constants.messageFirst,
},
};
// error on below line
const data = proxy.readQuery(options);
const _tmp = unshiftMessage(data, _message);
proxy.writeQuery({ ...options, data: _tmp });
},
})
.then(({ data }) => {
console.log("mutation complete", data);
console.log("mutation complete", data);
})
.catch((err) => console.log("Error creating message", err));
});
Analytics.record("Chat MSG Sent");
}
ERROR
errorHandling.js:7 Error: Can't find field allMessageConnection({"conversationId":"XXXXXXXXXXXXXXXXXXXXXXXXXXX","first":100}) on object {
"me": {
"type": "id",
"generated": false,
"id": "User:XXXXXXXXXXXXXXXXXXX",
"typename": "User"
}
}.

Related

PrismaClientValidationError: Missing required argument in connectOrCreate

Problem:When I try and send/store data in my database I get this error. Specifically, I am trying to create/save a classroom with student names.
Tech Used:
Prisma/Postgres connected to AWS RDS and Next.js, deployed on Vercel, etc.
Error Message
PrismaClientValidationError: Argument data.classrooms.upsert.0.create.students.connectOrCreate.0.create.school.connect of type schoolWhereUniqueInput needs at least one argument.
Argument data.classrooms.upsert.0.update.students.upsert.0.create.school.connect of type schoolWhereUniqueInput needs at least one argument.
at Document.validate (/var/task/node_modules/#prisma/client/runtime/index.js:29501:20)
at serializationFn (/var/task/node_modules/#prisma/client/runtime/index.js:33060:19)
at runInChildSpan (/var/task/node_modules/#prisma/client/runtime/index.js:22550:12)
at PrismaClient._executeRequest (/var/task/node_modules/#prisma/client/runtime/index.js:33067:31)
at async PrismaClient._request (/var/task/node_modules/#prisma/client/runtime/index.js:32994:16)
at async profile (/var/task/.next/server/pages/api/user/profile.js:175:27)
at async Object.apiResolver (/var/task/node_modules/next/dist/server/api-utils/node.js:366:9)
at async NextNodeServer.runApi (/var/task/node_modules/next/dist/server/next-server.js:481:9)
at async Object.fn (/var/task/node_modules/next/dist/server/next-server.js:735:37)
at async Router.execute (/var/task/node_modules/next/dist/server/router.js:247:36) {
clientVersion: '4.9.0'
}
DB Models with relationships: school (1 to many w/students); students (many to many with classrooms); teachers (one to many with students, many to many with classrooms)
Code/Prisma Query
export default async (req, res) => {
...
classroom.students.forEach((student) => {
const totalStudentPoints = student.rewardsRecieved.reduce(
(totalPoints, reward) => {
return totalPoints + reward.pointValue;
},
0
);
groups[student.group.name] += totalStudentPoints;
});
return { ...classroom, groupsTotalPoints: groups };
});
user.classrooms = newClassrooms;
res.json(user);
} else {
console.log("Could Not Find User");
res.status(401).json({
error: "Not authorized",
});
}
}
if (req.method === "PUT") {
const connectStudents = (shouldUpsert) => {
const students = req.body.students;
return students.map((student) => {
const UNSAFEHASH = md5(student.id);
const studentQuery: any = {
where: {
id: student.id,
},
create: {
id: student.id,
firstName: student.firstName,
lastName: student.lastName,
profilePicture: student.profilePicture,
userKey: UNSAFEHASH,
school: {
connect: {
id: req.body.schoolId,
},
},
group: {
connect: {
id: student.group.id,
},
},
},
};
if (shouldUpsert) {
studentQuery.update = {
firstName: student.firstName,
lastName: student.lastName,
profilePicture: student.profilePicture,
userKey: UNSAFEHASH,
group: {
connect: {
id: student.group.id,
},
},
};
}
return studentQuery;
});
};
try {
const user = await prisma.staff.update({
where: {
id: session.id,
},
data: {
firstName: req.body.firstName,
lastName: req.body.lastName,
classrooms: {
upsert: [
{
where: {
id: req.body.classId || "-1",
},
create: {
// id: req.body.classId,
name: req.body.className,
subject: req.body.classSubject,
students: {
connectOrCreate: connectStudents(false),
},
},
update: {
name: req.body.className,
subject: req.body.classSubject,
students: {
upsert: connectStudents(true),
},
},
},
],
},
},
});
Take a look at the PUT request and the prima.staff.update method more specifically. I was looking at the UPSERT I have there, but I can't figure out what's wrong.

Updating array of objects in Mongoose

I can't handle updating array of objects in my database, tried many options but nothing worked. Im pretty sure that the answer is obvious, but I couldn't manage it since wednesday.
Here is my kitSchema:
const kitSchema = new mongoose.Schema({
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
kit: {
type: Array,
required: true,
},
profiles: {
type: Array,
required: true,
},
});
module.exports = mongoose.model("Kit", kitSchema);
All users have their own document, and there are also profiles in it. I want to update single profile by passing the id of user and id of profile.
Example of data:
_id: 1,
email: "abc#mail",
password: "abc",
profiles: [
{
id: 1,
name: John
},
]
And here's my latest solution which doesn't work:
router.put("/profile/:id", async (req, res) => {
let kit = await Kit.findById(req.params.id, (error, data) => {
if (error) {
console.log(error);
} else {
console.log(data);
}
});
try {
await kit.profiles.findOneAndUpdate(
{ id: req.body.id },
{ name: req.body.name },
{ new: true },
(error, data) => {
if (error) {
console.log(error);
} else {
console.log(data);
}
}
);
try {
res.status(202).json({ message: "Changed" });
} catch (err) {
res.status(400).json({ message: err });
}
} catch (err) {
res.status(400).json({ message: err });
}
});
Could you give me a hand with this?
As always, after days of trying I've got answer 10 minutes after asking question. Here's what I came up with:
router.put("/profile/:id", async (req, res) => {
await Kit.findOneAndUpdate(
{ _id: req.params.id, profiles: { $elemMatch: { id: req.body.id } } },
{
$set: {
"profiles.$.name": req.body.name,
"profiles.$.profilePicture": req.body.profilePicture,
},
},
{ new: true, safe: true, upsert: true },
(error, data) => {
if (error) {
console.log(error);
} else {
console.log(data);
}
}
);
try {
res.status(202).json({ message: "Changed" });
} catch (err) {
res.status(400).json({ message: err });
}
});

MongoDB - JSON schema validation

Can anyone please tell me where to place the $jsonSchema in the following code. Every time I test post my code returns the status(400) success: false.
All I'm trying to do is validator the title and description have been entered correctly.
import { connectToDatabase } from "../../../util/mongodb";
export default async (req, res) => {
const { method } = req;
const { db } = await connectToDatabase();
switch (method) {
case "GET":
try {
const products = await db.collection("products").find({}).toArray();
res.status(200).json({ success: true, data: products });
} catch (error) {
res.status(400).json({ sucess: false });
}
break;
case "POST":
try {
const product = await db
.collection("products")
.insertOne(req.body)
.runCommand({
collMod: "products",
validator: {
$jsonSchema: {
bsonType: "object",
required: ["title", "description"],
properties: {
title: {
bsonType: "string",
description: "must be a string and is required",
unique: true,
},
description: {
bsonType: "string",
description: "must be a string and is required",
},
},
},
},
});
res.status(201).json({ success: true, data: product });
} catch (error) {
res.status(400).json({ sucess: false });
}
break;
default:
res.status(400).json({ dsucess: false });
break;
}
};

How do I use populate with callbacks?

User model
const Schema = mongoose.Schema
const userSchema = new Schema({
username: { type: String, required: true },
email: { type: String, reuired: true },
password: { type: String, required: true },
posts:[{ type: Schema.Types.ObjectId, ref: "Posts" }]
}, { timestamps: true })
Post model
const Schema = mongoose.Schema;
const postSchema = new Schema({
title: { type: String, required: true },
content: { type: String, required: true },
user: { type: Schema.Types.ObjectId, ref: "User" },
}, { timestamps: true }
endpoint for getting all posts with all users information
listPostsWithUsers: (req, res, next) => {
Post.find({}, (error, posts) => {
if (error) {
return res.status(500).json({ error: "something went wrong" })
} else if (!posts) {
return res.status(400).json({ msg: "sorry no posts" })
} else if (posts) {
return res.status(200).json({ posts })
}
})
}
The output should be the returned posts with the user object so that I can identify which post the user has posted.
Now, my question is how do I apply populate() method in the above endpoint. Mostly all examples are with exec() function but I've seen no example with callbacks. It's kind of a syntax problem.
Thank you.
Update#1: The result I'm getting currently.
{
"posts": [
{
"_id": "5e65cce5ebddec0c5cc925ab",
"title": "Neil's Post",
"content": "post by neil.",
"createdAt": "2020-03-09T04:58:13.900Z",
"updatedAt": "2020-03-09T04:58:13.900Z",
"__v": 0
},
{
"_id": "5e65cd32ebddec0c5cc925ad",
"title": "Slash's post",
"content": "post by slash.",
"createdAt": "2020-03-09T04:59:30.180Z",
"updatedAt": "2020-03-09T04:59:30.180Z",
"__v": 0
},
{
"_id": "5e65f430a989612916636e8d",
"title": "Jimmy's post",
"content": "post by jimmy",
"createdAt": "2020-03-09T07:45:52.664Z",
"updatedAt": "2020-03-09T07:45:52.664Z",
"__v": 0
}
]
}
Update#2
users collection.
{
"users": [
{
"posts": [],
"_id": "5e65ccbeebddec0c5cc925aa",
"username": "Neil",
"email": "neily888#gmail.com",
"password": "$2b$10$AHHRKuCX3nakMs8hdVj0DuwD5uL0/TJwkJyKZYR/TXPTrIo9f80IW",
"createdAt": "2020-03-09T04:57:35.008Z",
"updatedAt": "2020-03-09T04:57:35.008Z",
"__v": 0
},
{
"posts": [],
"_id": "5e65cd0eebddec0c5cc925ac",
"username": "Slash",
"email": "slash938#gmail.com",
"password": "$2b$10$QQX/CFJjmpGdBAEogQ4XO.1e1ZowuPCX7pJcHTUav7NfatGgp6sa6",
"createdAt": "2020-03-09T04:58:54.520Z",
"updatedAt": "2020-03-09T04:58:54.520Z",
"__v": 0
},
{
"posts": [],
"_id": "5e65f408a989612916636e8c",
"username": "Jimmy",
"email": "jimmy787#gmail.com",
"password": "$2b$10$/DjwWYIlNswgmYt3vo7hJeNupfBdFGe7p77uisYUViKv8IdhasDC.",
"createdAt": "2020-03-09T07:45:12.293Z",
"updatedAt": "2020-03-09T07:45:12.293Z",
"__v": 0
}
]
}
Update#3:
usersController
const User = require("../models/User")
module.exports = {
createUser: (req, res) => {
User.create(req.body, (err, createdUser) => {
if (err) console.log(err)
res.json({createdUser})
})
},
listUsers: (res) => {
User.find({}, (err, users) => {
if (err) console.log(err)
res.json({users})
})
},
getUser: (req, res) => {
User.findById(req.params.id, (err, user) => {
if (err) console.log(err)
return res.json({user})
})
},
updateUser: (req, res) => {
const user = {
username: req.body.username,
email: req.body.email,
password: req.body.password
}
User.findOneAndUpdate(req.params.id, user, { new: true }, (err, updatedUser) => {
if (err) console.log(err)
res.json({updatedUser})
})
},
deleteUser: (req, res) => {
User.findByIdAndDelete(req.params.id, (err, deleteduser) => {
if (err) console.log(err)
return res.status(200).json({ user: deleteduser })
})
}
}
postsController
const Post = require("../models/Post")
module.exports = {
createPost: (req, res) => {
const data = {
title: req.body.title,
description: req.body.description,
}
Post.create(data, (err, newPost) => {
if (err) console.log(err);
return res.status(200).json({ newPost })
})
},
listPosts: (res) => {
Post.find({}, async (err, posts) => {
if (err) console.log(err);
posts = await Post.populate(posts, {
path: "user",
model: "User"
})
return res.status(200).json({ posts })
})
},
findPost: (req, res) => {
Post.findById(req.params.id, (err, post) => {
if (err) console.log(err);
return res.json({ post })
}
)
},
updatePost: (req, res) => {
const post = {
title: req.body.title,
description: req.body.description
}
Post.findByIdAndUpdate(req.params.id, post, { new: true },(err, updatedPost) => {
if (err) console.log(err);
return res.status(200).json({ updatedPost })
})
},
deletePost: (req, res) => {
Post.findByIdAndDelete(req.params.id, (err, deletedPost) => {
if (err) console.log(err);
return res.status(200).json({ deletedPost })
})
}
}
Update#4
router.get("/posts/:id", usersController.getUserPosts) `
getUserPosts: (req, res) => {
User.findById(req.params.id, async (err, user) => {
if (err) {
return res.status(500).json({ error: "Server error" })
} else if (!user) {
return res.status(400).json({ error: "No user" })
} else if (user) {
user = await User.populate("user", {
path: "posts",
model: "Post"
})
return res.status(200).json({ user })
}
})
}
I suggest you to use mongoose populate.
listPostsWithUsers : (req, res, next) => {
Post.find({}).populate('user').exec(function (err, data) {
if (err) {
console.log(err);
} else {
console.log(data);
}
})
}
You can refer this official mongoose populate document
You can even populate as many fields required by using populate as
populate([{ path: 'user' }, { path: 'book', select: { author: 1 } }])
with the help of select in populate, you can project the required fields (get only those fields from populated collection.)
Edit 1
createPost: (req, res) => {
const data = {
title: req.body.title,
description: req.body.description,
user: req.user._id,
}
Post.create(data, (err, newPost) => {
if (err) console.log(err);
return res.status(200).json({ newPost })
})
You will need to add user field in post while creating.
take user id from token or from query and you would be good to go.
Edit 2
getUserPosts: (req, res) => {
User.findById(req.params.id).populate([{ path: 'posts' }])
.exec(function (err, data) {
if (err) {
console.log(err);
} else {
console.log(data);
}
});
}
You are finding data in user module and you want to populate post data, so you just need to say which field you want to populate as you have already defined on field which model to refer by adding ref with that field in mongoose schema.
getUserPosts: (req, res) => {
User.findById(req.params.id, async (err, user) => {
if (err) {
return res.status(500).json({ error: "Server error" })
} else if (!user) {
return res.status(400).json({ error: "No user" })
} else if (user) {
user = await User.populate("posts")
return res.status(200).json({ user })
}
})
}
This should also work for you.
You can do that after getting the posts as:
listPostsWithUsers: (req, res, next) => {
Post.find({}, async (error, posts) => {
if (error) {
return res.status(500).json({ error: "something went wrong" })
} else if (!posts) {
return res.status(400).json({ msg: "sorry no posts" })
} else if (posts) {
posts = await Post.populate(posts, {
path: 'user',
model: 'User'
});
return res.status(200).json({ posts })
}
})
}

trying to connect graphql to postgress how to define user and pass?

I fail to receive information from my postgres db when trying to connect with graphql.
I receive the following response:
{
"errors": [
{
"message": "password authentication failed for user \"admin\"",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"account"
]
}
],
"data": {
"account": null
}
}
I honestly don't know where to define the user and pass.
const express = require('express');
const expressGraphQL = require('express-graphql');
const schema = require('./schema');
const app = express();
app.use('/graphql', expressGraphQL({
schema,
graphiql: true
}))
app.listen(4000, () => {
console.log('Listening...')
})
and this is my schema file
const graphql = require('graphql');
const connectionString = 'myURI';
const pgp = require('pg-promise')();
const db = {}
db.conn = pgp(connectionString);
const {
GraphQLObjectType,
GraphQLID,
GraphQLString,
GraphQLBoolean,
GraphQLList,
GraphQLSchema
} = graphql;
const AccountType = new GraphQLObjectType({
name: 'account',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
busines_name: { type: GraphQLString },
email: {
type: new GraphQLList(EmailType),
resolve(parentValue, args) {
const query = `SELECT * FROM "emails" WHERE
account=${parentValue.id}`;
return db.conn.many(query)
.then(data => {
return data;
})
.catch(err => {
return 'The error is', err;
});
}
}
})
})
const EmailType = new GraphQLObjectType({
name: 'Email',
fields: {
id: { type: GraphQLID },
email: { type: GraphQLString },
primary: { type: GraphQLBoolean }
}
})
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
account: {
type: AccountType,
args: { id: { type: GraphQLID } },
resolve(parentValue, args) {
const query = `SELECT * FROM "account" WHERE id=${args.id}`;
return db.conn.one(query)
.then(data => {
return data;
})
.catch(err => {
return 'The error is', err;
});
}
},
emails: {
type: EmailType,
args: { id: { type: GraphQLID } },
resolve(parentValue, args) {
const query = `SELECT * FROM "emails" WHERE id=${args.id}`;
return db.conn.one(query)
.then(data => {
return data;
})
.catch(err => {
return 'The error is', err;
});
}
}
}
})
module.exports = new GraphQLSchema({
query: RootQuery
})
I would like to know where to define the user and the password for the db of what i'm doing wrong besides that.
const connectionString = 'myURI';
It should be enough if your connection string includes the username and password. Is your DB connection string of the form postgres://username:password#server:5432 ?
See https://www.postgresql.org/docs/10/libpq-connect.html#LIBPQ-CONNSTRING