Related
I’ve got a Next.JS app. I want to render a todo feed on the homepage, but also the user page. I'm a bit stuck on how to break down my Prisma queries.
I fetch a big data object using getServerSideProps and pass this to the page component (and using react-query to hydrate and do re-fetching, but not relevant now)
- getRecentTodos (includes todos) for my homepage
- getUserDetailsByName (includes todos) for the user page
export type getRecentTodos = ReturnType<typeof getRecentTodos> extends Promise<
infer T
>
? T
: never
export const getRecentTodos = async (recentItemsAmount = 20) => {
return await prisma.todos.findMany({
where: { done: true },
select: {
id: true,
userId: true,
content: true,
done: true,
createdAt: true,
attachments: true,
todoReplies: {
select: {
id: true,
userId: true,
content: true,
todoReplyLikes: true,
todoId: true,
user: { select: { name: true, displayName: true, image: true } },
},
orderBy: { createdAt: 'asc' },
},
todoLikes: {
select: {
user: true,
},
},
user: {
select: {
name: true,
displayName: true,
image: true,
},
},
},
orderBy: { createdAt: 'desc' },
take: recentItemsAmount,
})
}
export const getUserDetailsByName = async (username: string) => {
return await prisma.user.findUnique({
where: {
name: username,
},
select: {
name: true,
displayName: true,
bio: true,
location: true,
twitter: true,
image: true,
createdAt: true,
todos: {
select: {
id: true,
content: true,
userId: true,
done: true,
updatedAt: true,
createdAt: true,
attachments: true,
user: true,
todoLikes: true,
todoReplies: {
take: 30,
orderBy: { createdAt: 'desc' },
select: {
id: true,
userId: true,
todoId: true,
createdAt: true,
content: true,
user: true,
},
},
},
take: 30,
orderBy: { createdAt: 'desc' },
},
projects: true,
},
})
}
Both queries return ‘todos,’ but they can return it in a slightly different way. The todo feed component expects certain properties to be available
- E.g. displayName on todoReplies
- But on getUserDetailsByName the displayName might not be part of the response or it’s nested one layer deeper or something
How to keep this from getting complex very fast?
You more or less want to select todos in your queries the same way (returning the same and omitting the same, apart of some things like order)
But manually keeping these things in sync over lot’s of queries qet’s complex quickly
Possible solutions?
Should I break the getServerSideProps into multiple fetches?
So instead of one ‘getUserDetailsByName’ which has todos as a relationfield included
fetch user details
fetch todos
This would mean I also have to write more react-query code for refetching etc… because you are dealing with multiple objects. But it does seperate concerns more.
Using Typescript to catch it in my codebase when a function tries to access a property which is not returned from that specific Prisma query? (I’m just now starting to see the possibilities of Typescript for stuff like this)
Should I just standardize the way the todos get created in a prisma query with a function and include that function inside of the Prisma queries? you can include like:
const todoSelect = {
id: true,
userId: true,
content: true,
{.......}
user: {
select: {
name: true,
displayName: true,
image: true,
},
},
}
export type getRecentTodos = ReturnType<typeof getRecentTodos> extends Promise<
infer T
>
? T
: never
export const getRecentTodos = async (recentItemsAmount = 20) => {
return await prisma.todos.findMany({
where: { done: true },
select: todoSelect,
orderBy: { createdAt: 'desc' },
take: recentItemsAmount,
})
}
const userSelect = {
name: true,
{......}
todos: {
select: todoSelect,
take: 30,
orderBy: { createdAt: 'desc' },
},
projects: true,
}
export const getUserDetailsByName = async (username: string) => {
return await prisma.user.findUnique({
where: {
name: username,
},
select: userSelect,
})
}
Hi I building login form and doing authentication with using nextjs , nextauthjs and mysql
these are my codes .
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials"
import { query } from "../getdata";
import axios from "axios";
import { Users } from "../../../../server/models/Users";
import mysql from 'mysql2';
export default NextAuth({
session: {
strategy: 'jwt',
},
callbacks: {
async jwt({ token, user }) {
if (user?.id) token.id = user.id;
return token;
},
async session({ session, token }) {
if (token?.id) session.user.id = token.id;
return session;
},
},
providers: [
CredentialsProvider({
name: "credentials",
credentials: {
username: {
label: "username",
type: "text",
placeholder: "johndoe#test.com",
},
password: { label: "Password", type: "password" },
},
authorize: async (credentials) => {
const user = await Users.findOne({ where: { username: credentials.username } });
console.log()
// database look up
if (
credentials.username === user.username &&
credentials.password === user.password
) {
return {
name: "John",
email: "johndoe#test.com",
};
} else {
throw new Error(errorMessage);
}
},
}),
],
});
I am getting this error when I am logging in
Cannot read properties of undefined (reading 'findOne')
Here are data for /models/Users i used this in next auth js.
once i used these code in express there its worked fine same thing i am doing in nextauth but it gives me error
module.exports = (sequelize, DataTypes) => {
const Users = sequelize.define("Users", {
username: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
role: {
type: DataTypes.STRING,
allowNull: false,
},
});
return Users;
};
Why I'm getting this error!!
GOOGLE USER: null
/Users//my-blog/api/node_modules/mongodb/lib/operations/insert.js:53
return callback(new error_1.MongoServerError(res.writeErrors[0]));
^
MongoServerError: E11000 duplicate key error collection: blog.users
index: email_1 dup key: { email: "" }
I dropped the whole collection in Mongodb and when I tried again it gave me the same error but the data stored in MongoDB collection, the problem is with the error it stops the whole app from running. I don't know where I went wrong or what I'm missing.
Auth.js Code:
router.get("/google", passport.authenticate("google", {
scope: ["profile", "email"] }));
router.get("/auth/google/callback", passport.authenticate("google", {
successRedirect: "http://localhost:3000/",
failureRedirect: "/googleLogin/failed"
}));
router.get("/googleLogin/success", async (req, res)=>{
if(req.user){
const user = await User.findOne({provider_id: req.user.id,
provider: req.user.provider})
if(user){
res.status(200).json({
success: true,
message: "success",
user: user
})
console.log("GOOGLE USER IS: " + user)
}else{
const checkUserEmail = await User.findOne({email: req.user.email})
if(checkUserEmail){
res.status(401).json({
success: false,
message: "User already Exist with this email id",
})
}else{
const user = await User.create({
username: req.user.name.givenName+ "_" +req.user.name.familyName,
firstName: req.user.name.givenName,
lastName: req.user.name.familyName,
email: req.user.emails[0].value,
provider: req.user.provider,
provider_id: req.user.id,
// profilePic: req.user.photos?.[0]?.value,
});
res.status(200).json({
success: true,
message: "success",
user: user
})
}
}
console.log("GOOGLE USER: ", user);
}
})
router.get("/googleLogin/failed", (req, res)=>{
if(req.user){
res.status(401).json({
success: false,
message: "failure",
})
}
})
I THINK the code keeps running nonstop ! thats why it giving me the error even so the collection is empty, it sign up the user then it sign up again non stop. I think that it should be a done() in the code but I didn't know how to fix it.
Passport.js Setup:
passport.use(new GoogleStrategy({
clientID: process.env.REACT_APP_GOOGLE_CLIENT_ID,
clientSecret: process.env.REACT_APP_GOOGLE_CLIENT_SECRET,
callbackURL: "/auth/google/callback",
passReqToCallback: true,
scope: ["profile", "email"],
},
function(request, accessToken, refreshToken, profile, done){
console.log(profile.emails[0].value);
console.log(profile.photos[0].value);
return done(null, profile)
}
));
passport.serializeUser((user, done)=>{
done(null, user)
})
passport.deserializeUser((user, done)=>{
done(null, user)
})
Here is my User Schema: User.js
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: false,
/* Can't create a user with the same username */
unique: true,
minlength: 3,
maxlength: 30,
},
firstName: {
type: String,
required: false,
unique: false,
maxlength: 20,
},
lastName: {
type: String,
required: false,
unique: false,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
},
repeatPassword: {
type: String,
},
profilePic: {
type: String,
default: "",
},
birthday: {
type: String,
required: false,
unique: false,
},
country: {
type: String,
required: false,
unique: false,
},
googleId: {
type: String
},
provider: {
type: String,
default: "email"
},
provider_id: {
type: String,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("User", UserSchema);
I'm working on a web site where users can have a project, and for each project they have, they are assigned a certain role. Here is the schema
How I can make it with the model of squelize (Or maybe it's better to don't use an ORM (it's what I'm thinking right now..))
Here you can see a part of my model :
//Users
module.exports = function(sequelize, DataTypes) {
return sequelize.define('User', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
// ******** //
}, {
tableName: 'users',
freezeTableName: true
});
};
//Projects
module.exports = function(sequelize, DataTypes) {
return sequelize.define('Project', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING,
allowNull: true
}
}, {
tableName: 'projects',
freezeTableName: true
});
};
//ProjectRole :
module.exports = function(sequelize, DataTypes) {
return sequelize.define('ProjectRole', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING,
allowNull: true
}
}, {
tableName: 'projects_roles',
freezeTableName: true
});
};
//user has projects :
module.exports = function(sequelize, DataTypes) {
return sequelize.define('UserProject', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
}, {
tableName: 'users_has_projects',
freezeTableName: true
});
};
I'm working on a NodeJS+Sequelize+jade web-app. I have a table called box and another one called user. The user has a one-to-many relation with box. What I like to do is list and show in a jade-template all the box details, including the user who owns it.
First I created the tables using sequelize tools
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING,
allowNull: false
},
dateOfBirth: DataTypes.DATE,
role: {
type: DataTypes.ENUM,
values: ['ADMIN', 'USER'],
defaultValue: 'USER'
}
},{
classMethods:{
associate: function(models) {
User.hasMany(models.Box);
}
})
return User;
};
The same to box:
module.exports = function(sequelize, DataTypes) {
var Box = sequelize.define('Box',{
boxTitle: {
type : DataTypes.STRING,
allowNull: false
},
lifetime: {
type : DataTypes.DATE,
allowNull : false
},
status: {
type: DataTypes.ENUM,
values: ['ACTIVE', 'NOTACTIVE'],
defaultValue: 'ACTIVE'
},
count: {
type: DataTypes.INTEGER,
allowNull : false
}
},{
classMethods:{
associate: function(models) {
Box.belongsTo(models.User);
}
});
return Box;
};
So, when I put some data in the database, I'm trying to print te box information:
each box in boxes
each user in box.users
tr
td= box.getDataValue('boxTitle')
td= user.getDataValue('name')
td= box.getDataValue('lifetime')
td= box.getDataValue('count')
td= box.getDataValue('status')
I did this so far, but I'm getting an error:
Cannot read property 'length' of undefined
I believe the program is not recognizing the association between those two tables, but I'm not sure.
Does anyone knows how can I solve this problem, or maybe to it in a different way?
I would be very grateful if you could help me.