Prisma result processing into single object - javascript

I'm working on a nextjs 13 project with prisma ORM with MongoDB. Currently I am trying to fetch roles with permissions for admin role matrix. This is the Role model schema.
model Role {
id String #id #default(auto()) #map("_id") #db.ObjectId
name String #unique
userIDs String[] #db.ObjectId
users User[] #relation(fields: [userIDs], references: [id])
permissions String[]
##map("roles")
}
When fetching the records I'd like to process them a little. Running this query returns such result.
const roles = await prisma.role.findMany({
select: {
name: true,
permissions: true,
}
})
console.log(roles);
[
{ name: 'User', permissions: [ 'permissions.user.view.dashboard' ] },
{
name: 'Admin',
permissions: [
'permissions.admin.view.dashboard',
'permissions.user.view.dashboard'
]
}
]
I need the results in one object with role name prepended to the permission like so
{
'User.permissions.user.view.dashboard',
'Admin.permissions.user.view.dashboard',
'Admin.permissions.admin.view.dashboard'
}
So my question is how would I do this? Preferably directly in prisma, but if it's not possible javascript will do.

It's not possible to transform this object directly at Prisma level.
You can achieve this transformation like this:
import { PrismaClient } from '#prisma/client';
const prisma = new PrismaClient();
async function main() {
const roles = await prisma.role.findMany({
select: {
name: true,
permissions: true,
},
});
console.log(roles);
const updatedRoles = [];
roles.forEach((role) => {
role.permissions.forEach((permission) => {
updatedRoles.push(`${role.name}.${permission}`);
});
});
console.log(updatedRoles);
}
main()
.catch((e) => {
throw e;
})
.finally(async () => {
await prisma.$disconnect();
});
Here's the sample response:

Related

Prisma findMany function is not returning relational data

I am trying to populate my data with relational data using Prisma 2.28.0, Here is my
Schema.prisma model below
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Product {
id Int #id #default(autoincrement())
name String #db.VarChar(255)
transactions Transaction[]
}
model Transaction {
id BigInt #id #default(autoincrement())
quantity Int
time Int
product Product? #relation(fields: [productId], references: [id])
productId Int?
}
the function I am trying to fetch data.
const { PrismaClient }=require("#prisma/client")
const prisma = new PrismaClient()
async function checkPrismaConnection(){
try {
const result=await prisma.product.findMany();
console.log(result);
}catch (e) {
console.log(e);
}
}
checkPrismaConnection();
OutPut
[
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Masum' },
{ id: 3, name: 'Rezaul' }
]
Transaction DB result
Product DB
I don't know why my findMany() is not retuning relational db data. Thank you
I suggest reading the documentation, especially this chapter and the ones following that. In their example, they have an Author and Post, where Post has an author field pointing at an Author. Their code looks like this:
const getPosts = await prisma.post.findMany({
where: {
title: {
contains: 'cookies',
},
},
include: {
author: true, // Return all fields
},
})
The chapter "Include deeply nested relations" a bit lower actually uses a field .category that's also an array, as in your example with .transactions.
You need to explicitly set include to true.
So the code will look like this for you
const { PrismaClient }=require("#prisma/client")
const prisma = new PrismaClient()
async function checkPrismaConnection(){
try {
const result=await prisma.product.findMany({
include: {
transaction: true,
},
});
console.log(result);
}catch (e) {
console.log(e);
}
}
checkPrismaConnection();

TypeORM - add object to OneToMany relations

I have a user and project entity with OneToMany relations between them,
user.entity.ts
#ManyToOne(() => Project, pro => pro.members, {
nullable: true
})
#JoinColumn({
name: 'userId',
})
member: Project;
project.entity.ts
#OneToMany(() => User, user => user.member)
members: User[]
function to add user to project:
async addMemberToProject(projectId: number, memberEmail: string): Promise<void> {
const project = await this.conn.getRepository(Project).findOne({
where: {
id: projectId
}
}).catch(() => {
throw new BadRequestException("Project not found!");
});
const user = await this.getUserByEmail(memberEmail).catch(() => {
throw new BadRequestException("User not found!");
})
if(user !== null) {
project.members.push(user);
await this.conn.getRepository(Repository).save(project).catch(() => {
throw new BadRequestException("Member not added to project!");
});
}
}
why when I try to add user to project, my compiler throw me:
Cannot read property 'push' of undefined
What i'm doing wrong? Maybe I have a bad database logic? (User can be in many projects, project can have many users), Can someone help me? Thanks for any help!
#JoinColumn on the user.entity looks wrong, it should be named: projectId, assuming the primary key of Project.entity is projectId.
The reason for you error is you need to add relations: ['members'] to project findOne()
const project = await this.conn.getRepository(Project).findOne({
where: {
id: projectId
},
relations: ['members']
})
Without this, TypeORM does not populate "project.members": project.members is undefined, so project.members.push(user) causes an "undefined" error.

Prisma throws an error "TypeError: cannot read property findmany of undefined"

I wanted to make a chat app to practice working with graphql and node, for database I used prisma. I was doing everything like in this tutorial.
https://www.howtographql.com/graphql-js/0-introduction/
I just changed variable names.
so I have this code
const { PrismaClient } = require('#prisma/client')
const prisma = new PrismaClient()
const resolvers = {
Query: {
history: async (parent, args, context) => {
return context.prisma.Messages.findMany()
},
},
Mutation: {
post: (parent, args, context) => {
const newMessage = context.prisma.Messages.create({
data: {
username: args.username,
message: args.message,
},
})
return newMessage
},
},
}
const server = new GraphQLServer({
typeDefs: './src/schema.graphql',
resolvers,
context: {
prisma,
}
})
server.start(() => console.log(`Server is running on http://localhost:4000`))
as my index.js
this is my schema.prisma
provider = "sqlite"
url = "file:./dev.db"
}
generator client {
provider = "prisma-client-js"
}
model Message {
id Int #id #default(autoincrement())
sendedAt DateTime #default(now())
message String
username String
}
script.js
const { PrismaClient } = require("#prisma/client")
const prisma = new PrismaClient()
async function main() {
const newMessage = await prisma.Messages.create({
data: {
message: 'Fullstack tutorial for GraphQL',
username: 'www.howtographql.com',
},
})
const allMessages = await prisma.Messages.findMany()
console.log(allMessages)
}
main()
.catch(e => {
throw e
})
// 5
.finally(async () => {
await prisma.disconnect()
})
and schema.graphql
type Query {
history: [Message!]!
}
type Mutation {
post(username: String!, message: String!): Message!
}
type Message {
id: ID!
message: String!
username: String!
}
and that is what i got in my playground
"data": null,
"errors": [
{
"message": "Cannot read property 'findMany' of undefined",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"history"
]
}
]
}
please help
I managed to fix that. Actually, all I needed was to use the same name but lowercased as in schema.prisma
It should be noted it is not actually lowercase but camel case.
Example:
Model name: Message -> Prisma client name: message
Model name: MessagePerUser -> Prisma client name: messagePerUser
Would like to add on to the answer
Basically when calling await prisma.User.create, prisma allows the User model to be in caps, but when calling other models such as prisma.messages.create the m has to be in lowercase. Essentially,for all prisma calls, the models should be in lowercase. Hopefully this answers your question, prisma does not flag this error out
use Table name as camelCase in prisma Client to make Queries
Example:
Table Name is: StudentData
then use camelCase according to table name
prisma.studentData.findMany();

Issues joining tables in GraphQL resolvers, thrown 400 error

I am trying to join MySQL tables using GraphQL and keep receiving a 400 error code:
"Response not successful: Received status code 400"
This is how I am querying my data:
{
users {
usr_last_name
business {
bus_name
}
}
}
# or
{
user(usr_id:1) {
usr_last_name
business {
bus_name
}
}
}
Here are my resolvers for User.
export const resolvers = {
Query: {
users: async() => db.user.findAll(),
user: async(obj, args, context, info) => db.user.findByPk(args.usr_id)
},
Mutation: {...},
User: {
business: async(obj, args, context, info) => { // This is not getting hit :/
return db.business.findAll({where: {bus_user_id: args.usr_id}});
}
}
};
(Note that I can query Business with no issues)
Thanks,
The problem was I forgot to put business: Business in the type definition for the type user:
type User {
usr_id: ID
usr_first_name: String
usr_last_name: String
usr_email: String
usr_password: String
usr_create_date: Int
usr_delete_date: Int,
business: Business
}

MongoDB: remove skill from user document

So I have an issue. I have a MongoDB user document and this document has a property skills, which is an array filled with objects.
What I want to do now is the following. The client sends a request to delete one of these skills. So I send the skill ID and then I want to remove the skill from the user. How could I do this?
What I currently have: every item in the skills property array has a skill property which is an objectID. When this objectID matches the objectId that the client sent, then we want to remove this skill from the user
const removeSkill = async (req, res) => {
try {
const { userId, params: { skillId } } = req;
const user = await User.findByIdAndUpdate({ _id: userId }, {
$pull: { "skills.skill": skillId }
}, {
new: true
});
return res.status(200).json({
message: 'succesfully removed skill',
user
});
} catch (err) {
return sendErr(res, err);
}
};
What the user mongodb document looks like
The error I get
:no_entry: Error:
MongoError: Cannot use the part (skill) of (skills.skill) to traverse the element ({skills: [ { _id: ObjectId('5c8729be12e1cc05c04ea182'), name: "javascript", skill: ObjectId('5c8729be
12e1cc05c04ea181'), points: 22 }, { _id: ObjectId('5c8729dc12e1cc05c04ea184'), name: "node.js", skill: ObjectId('5c8729dc12e1cc05c04ea183'), points: 14 }, { _id: ObjectId('5c872a6c12e1c
c05c04ea186'), name: "css", skill: ObjectId('5c872a6c12e
First of all you shouldn't be using 2 Object ID in one object. The beauty of MongoDB is auto generated ObjectID. For your question (using skill ObjectID)
const user = await User.findByIdAndUpdate(
{ _id: userId },
{ $pull: { "skills": { skill: skillId }}},
{ new: true}
);
I believe u are receiving ObjectID from your params. If so,Something like this should help.

Categories