Prisma upsertmany issue Provided List<Json>, expected SimilarCreateWithoutMovieInput - node.js

using "#prisma/client": "^2.25.0"
on prisma.upsertOneMovie. Provided List<Json>, expected SimilarCreateWithoutMovieInput or SimilarCreateWithoutMovieInput or SimilarUncheckedCreateWithoutMovieInput or SimilarUncheckedCreateWithoutMovieInput:
[0] type SimilarCreateWithoutMovieInput {
[0] id: Int
[0] backdrop_path: String
[0] title: String
[0] name: String
[0] release_date: DateTime
[0] overview: String
[0] show: TVShowCreateNestedOneWithoutSimilarInput
[0] }
code
const { PrismaClient } = require('#prisma/client')
const prisma = new PrismaClient()
...
let result = await apiRequest
let similar = result.similar.results.map(similar_movie => {
return {
id: similar_movie.id,
backdrop_path: similar_movie.backdrop_path,
title: similar_movie.title,
name: similar_movie.name,
release_date: similar_movie.release_date,
overview: similar_movie.overview,
movieId: result.id
}
})
const movie = {
id: result.id,
...
similar: {
upsert: similar
}
}
const upsertMovie = await prisma.movie.upsert({
where: { id: movie.id },
update: movie,
create: movie,
})
here is the schema.prisma
model Movie {
id Int #id
...other fields and attributes...
similar Similar[]
}
model Similar {
id Int #id #default(autoincrement())
tmdb_id Int #unique
backdrop_path String
title String?
name String?
release_date String
overview String
movie Movie? #relation(fields: [movie_id], references: [id])
show TVShow? #relation(fields: [show_id], references: [id])
movie_id Int?
show_id Int?
}
Similar is supposed to be an array [] of other Movies nested in a specific Movie object, cant be itself
I do not have experience with prisma upsert on generated types and I am getting the above error. Im expecting to upsert a Movie and at the same time upsert multiple records of Similar that are related to Movie.
i have tried using connectOrCreate but it does not support creating multiple records of similar while creating one record of movie as expected
how do I achieve that?
resources
https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#nested-writes
https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#connect-or-create-a-record

Issue was that prisma createMany is not available on sqlite, and on the postgresql connector, it is.
const movie = {
...result,
similar: {
connectOrCreate: result.similar.map(s => ({
create: s,
where: { id: s.id },
}))
}
}
const upsertMovie = await prisma.movie.upsert({
where: { id: movie.id },
update: movie,
create: movie,
})

Related

Can't disconnect relation of explicit many-to-many

I'm trying to delete some users which are related to a group.
Here is the schema:
model User {
id String #id #default(cuid())
username String
email String #unique
password String?
group GroupUser[]
}
model Group {
id String #id #default(cuid())
name String
user GroupUser[]
}
model GroupUser{
userId String
user User #relation(fields: [userId],references: [id],onDelete: Cascade,onUpdate:Cascade)
groupId String
group Group #relation(fields: [groupId],references: [id],onDelete: Cascade,onUpdate: Cascade)
##id([userId,groupId])
}
The code to delete the users:
async deleteUsersFromGroup(id: string, userData: UpdateGroupDto): Promise<number> {
const deletedUsers = await prisma.group.update({
where: {
id: id,
},
data: {
user: { disconnect: /* trying to put the array of users id here */ },
},
});
return deletedUsers.length;
}
The problem is that I want to give the userID inside of the disconnect but it is asking me for userId_groupId which is the relational key.
You would need to delete the record from the connecting table i.e. GroupUser.
You can try something like this:
await prisma.groupuser.delete({
where: {
userId_groupId: {
userId: 'userId',
groupId:'groupId'
}
}
});
If the connecting records are deleted then both the entities would be disconnected.
Since I wanted to delete multiple users at the same time I used the map function inside userId, resorting to prisma.groupUser.delete().
async deleteUsersFromGroup(id: string, userData: DeleteGroupDto): Promise<any> {
const response = await prisma.groupUser.deleteMany({
where: {
groupId: id,
userId: { in: userData.users.map(user => user.userId) },
},
});
return response.count
}

Update parent and upsert child in Prisma

I have a parent-child relation like below:
model User {
id Int #id #default(autoincrement())
authId String #unique #default("N/A") #map("auth_id") #db.VarChar(128)
email String #unique #db.VarChar(256)
firstName String #map("first_name") #db.VarChar(64)
lastName String #map("last_name") #db.VarChar(64)
profile Profile?
}
model Gender {
id Int #id #default(autoincrement())
text String
Profile Profile[]
}
model MedicalCondition {
id Int #id #default(autoincrement())
text String
Profiles Profile[]
}
model Profile {
id Int #id #default(autoincrement())
dob String #db.VarChar(32)
weightLbs Float #map("weight_lbs")
heightIn Int #map("height_in") #db.SmallInt
user User #relation(fields: [userId], references: [id], onDelete: Cascade)
userId Int #unique #map("user_id")
gender Gender #relation(fields: [genderId], references: [id])
genderId Int #map("gender_id")
lifeStyle LifeStyle? #relation(fields: [lifeStyleId], #map("life_style_id")
medicalConditions MedicalCondition[]
}
I'm quite new to node.js and Prisma and I'm wondering is it possible to update User and upsert Profile together like below?
const updateWithProfile = (where: IUserUniqueInput, data: IUserUpdate, medicalConditions?: IMedicalConditionWhereUniqueInput[]): Promise<IUser> => {
return user.update({
where,
data:{
...data,
profile: {
upsert:{
????
},
}
}
});
};
Here is my working solution for upsert one-to-one and many-to-many relations:
const update = async (
data: IProfileUpdate,
medicalConditions?: IMedicalConditionWhereUniqueInput[]
): Promise<IProfile> => {
return profile.upsert({
where: {
userId: data.userId,
},
update: {
...data,
// set removes previous values in mapping table and connect inserts new IDs
medicalConditions: { set: [], connect: medicalConditions }
},
create: {
...data,
medicalConditions: { connect: medicalConditions }
}
});
};

Sequelize upsert or create without PK

I'm unable to perform any kind of upsert or create within Sequelize (v: 6.9.0, PostGres dialect).
Using out-of-the-box id as PK, with a unique constraint on the name field. I've disabled timestamps because I don't need them, and upsert was complaining about them. I've tried manually defining the PK id, and allowing Sequelize to magically create it. Here's the current definition:
const schema = {
name: {
unique: true,
allowNull: false,
type: DataTypes.STRING,
}
};
class Pet extends Model { }
Pet.define = () => Pet.init(schema, { sequelize }, { timestamps: false });
Pet.buildCreate = (params) => new Promise((resolve, reject) => {
let options = {
defaults: params
, where: {
name: params.name
}
, returning: true
}
Pet.upsert(options)
.then((instance) => {
resolve(instance);
})
.catch(e => {
// message:'Cannot read property 'createdAt' of undefined'
console.log(`ERROR: ${e.message || e}`);
reject(e);
});
});
module.exports = Pet;
Upsert code:
// handled in separate async method, including here for clarity
sequelize.sync();
// later in code, after db sync
Pet.buildCreate({ name: 'Fido' });
In debugging, the options appear correct:
{
defaults: {
name: 'Fido'
},
returning:true,
where: {
name: 'Fido'
}
}
I've also tried findOrCreate and findCreateFind, they all return errors with variations of Cannot convert undefined or null to object.
I've tried including id: null with the params, exact same results.
The only way I've succeeded is by providing PK in the params, but that is clearly not scalable.
How can I upsert a Model instance without providing a PK id in params?
class Pet extends Model { }
//...you might have the id for the pet from other sources..call it petId
const aPet = Pet.findCreateFind({where: {id: petId}});
aPet.attribute1 = 'xyz';
aPet.attribute2 = 42;
aPet.save();

How to upsert new record in Prisma without an ID?

I'm using Prisma (https://www.prisma.io) as ORM. I want to check for duplicates when store data and, if not exists, create a new record.
I thought I could do that with upsert method provided by Prisma and available in the generated client, but the where clause of that method only works with id (or #unique fields), but if the record doesn't exist, there isn't any id to provide.
I provide an example of the problem.
datamodel.prisma
type System {
id: ID! #unique
performances: [SystemPerformance!]! #relation(name: "PerformanceBySystem" onDelete: CASCADE)
name: String! #unique
}
type SystemPerformance {
id: ID! #unique
system: System! #relation(name: "PerformanceBySystem")
date: DateTime!
perf1: Float
perf2: Float
}
seed.js
const { prisma } = require('./generated/prisma-client');
async function main(){
await prisma.createSystem({
name: 's1',
});
await prisma.createSystem({
name: 's2',
});
await prisma.createSystem({
name: 's3',
});
}
main();
After creation there is a database with three Systems without performances. I'm trying to insert a new SystemPerformance if there aren't any that have same date and same System. I have tried
const { prisma } = require('./prisma/generated/prisma-client');
const perf = await prisma.upsertSystemPerformance({
where: {
system: {name: 's1'},
date: "2019-03-12T00:01:06.000Z"
},
update: {
perf1: 13.45,
perf2: 18.93
},
create: {
system: {
connect: { name: 's1' }
},
date: "2019-03-12T00:01:06.000Z",
perf1: 13.45,
perf2: 18.93
}
})
But an exception is thrown:
UnhandledPromiseRejectionWarning: Error: Variable '$where' expected value of type 'SystemPerformanceWhereUniqueInput!' but got: {"system":{"name":'s1'},"date":"2019-03-12T00:01:06.000Z"}. Reason: 'system' Field 'system' is not defined in the input type 'SystemPerformanceWhereUniqueInput'
The only solution I have found is check for existence and then update or create, but I wanted to do it with upsert.
let check = await prisma.$exists.SystemPerformance({
system: {name: 's1'},
date: "2019-03-12T00:01:06.000Z"
});
let perfo;
if (check){
const sysPerf = await prisma.systemPerformances({where:{system: {name: 's1'}, date: "2019-03-12T00:01:06.000Z"}})
.$fragment(`
{
id
}
`);
perfo = await prisma.updateSystemPerformance({
where: {id: sysPerf[0].id},
data: {
perf1: 13.45,
perf2: 18.93
}
})
}
else {
perfo = await prisma.createSystemPerformance({
system: {
connect: { name: 's1' }
},
date: "2019-03-12T00:01:06.000Z",
perf1: 13.45,
perf2: 18.93
}
})
Is there a way to do that with upsert?
The fields in where need to be unique.
If you can make some field, let's say date #unique (date: DateTime! #unique), and use that for your where in the upsert, I think it would work (tested on my local)
where: {
id: sysPerf[0].id ? sysPerf[0].id : 0
},

How should I write a resolver while using apollo graphql server backed by neo4j database?

I am using neo4j dB and I have set up apollo graphql server (using graphql-server-express). Lets say my schema has 3 types namely "Country", "State" and "People" where 1 country can have multiple states and 1 state can have multiple people.
//Sample schema.js
import { makeExecutableSchema } from 'graphql-tools';
import resolvers from './resolvers';
const typeDefs = `
type Country {
id: Int!
name: String
state: [State]
people: [People]
}
type State {
id: Int!
name: String
countryID: CountryID
people: [People]
}
type People {
id: Int!
name: String
SSN: String
stateid:StateID
countryid:CountryID
}
type Query {
Countries: [Country]
States: [State]
Peoples: [People]
}
schema {
query: Query
}
`;
export default makeExecutableSchema({
typeDefs: typeDefs,
resolvers,
});
So, how should I write my resolver function in resolver.js file such that it would help me to fetch the data properly from any of the above types ?
I tried to use the following query in resolver.js file (to query the Neo4j database using Cypher query language), but got the type error and i am unable to fix it.
//Sample resolver.js file.
let neo4j = require('neo4j-driver').v1;
let driver = neo4j.driver("bolt://localhost", neo4j.auth.basic("neo4j",
"******"));
const resolver = {
Query: {
Countries(_, params) {
let session = driver.session();
let query = "MATCH (country:Country) RETURN country;"
return session.run(query, params)
.then( result => { return result.records.map(record => { return
record.get("country").properties })})
},
},
State:{
state(State) {
let session = driver.session(),
params = {countryid: Country.id},
query = `
MATCH (s:State-[:PRESENT]->(c:Country)
WHERE s.countryid = $countryid
RETURN s;
`
return session.run(query, params)
.then( result => { return result.records.map(record => { return
record.get("state").properties })})
},
},
};
export default resolver;

Resources