how to query object in mongo using prisma - mongodb

I want to query by using where in object with prisma and mongo
Here is my prisma schema
model Member {
id String #id #default(auto()) #map("_id") #db.ObjectId
bank BankInfo
##map("members")
}
type BankInfo {
bankNo String
}
const member = await this.prisma.member.findFirst({
where: { bank: { bankNo: 'test' } },
});
I got an error
Error:
Invalid prisma.member.findFirst() invocation:

You can try to use equal operator ($eq) like that :
const member = await this.db.member.find({
bank: { $eq: { bankNo: 'test' } }
})

Related

Why fields in same hierarchy get deleted when updating in Prisma?

I am trying to implement updation using prisma.
here is my data structure.
{
"name":"toy",
"data":{
"sports":{
"currentState":"false",
"oldState":"true"
}
}
Here is my logic to update currentState from false to true.
const updatedSource = await prisma.sources.update({
where: {
name: 'toy'
},
data: {
data: {
update:{
sports: {
currentState: "true"
}
}
}
},
})
Here is the schema file:
type SourcesData {
sports SourcesDataState
}
type SourcesDataState {
currentState String
oldState String
}
model sources {
id String #id #default(auto()) #map("_id") #db.ObjectId
data SourcesData
name String #unique
}
The above logic updates the currentState field but deletes the oldState field from the database.
Please guide me on how to update currentState in a way that oldState data persists.

How to define models with nested objects in prisma?

I am trying to migrate from mongoose to Prisma. Here is the model I have defined in mongoose which contains nested objects.
const sourceSchema = new Schema(
{
data: {
national: {
oldState: {
type: Array
},
currentState: {
type: Array
}
},
sports: {
oldState: {
type: Array
},
currentState: {
type: Array
}
}
}
}
);
Please guide me on how can I write the model in Prisma for the mongoose schema with nested objects.
You are looking for composite types to store nested objects in Prisma.
Here's how you can define the models:
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
model Source {
id String #id #default(auto()) #map("_id") #db.ObjectId
national stateType
sports stateType
}
type stateType {
oldState oldState
currentState currentState
}
type oldState {
type String[]
}
type currentState {
type String[]
}

Referenced objects in DB returning null in GraphQL Query

I have the following database model:
Each Mediablock contains a reference to exactly one UTS object and one Media object.
Each UTS object contains rawText and normalisedText
Each Media object contains a url and a timestamp
My schema.prisma looks like this:
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model Mediablock {
id String #id #default(auto()) #map("_id") #db.ObjectId // gen a new, unique id
UTS UTS #relation(fields: [utsId], references: [id])
utsId String #unique #map("uts_id") #db.ObjectId
Media Media #relation(fields: [mediaId], references: [id])
mediaId String #unique #map("media_id") #db.ObjectId
}
model UTS {
id String #id #default(auto()) #map("_id") #db.ObjectId
rawText String
normalisedText String
createdAt DateTime #default(now())
Mediablock Mediablock?
}
// // Mediablocks contain a Video object and connect back to the Mediablock.
// // mediablockId must have #db.ObjectId to match up with Mediablock's id type
model Media {
id String #id #default(auto()) #map("_id") #db.ObjectId
url String
createdAt DateTime #default(now())
Mediablock Mediablock?
}
My resolvers look like this:
const { PrismaClient } = require('#prisma/client');
const prisma = new PrismaClient();
//This resolver retrieves mediabooks from the "mediabooks" array above.
module.exports = {
Query: {
allMediablocks: () => prisma.mediablock.findMany(),
allMedia: () => prisma.media.findMany(),
allUTS: () => prisma.uts.findMany(),
},
};
And my typedefs looks like this:
module.exports = `
type Mediablock {
id: ID!
uts: UTS
media: Media # can be null when the text is generated first
}
type UTS {
id: ID!
rawText: String!
normalisedText: String!
}
type Media {
id: ID!
url: String!
createdAt: String!
}
# The "Query" type is special: it lists all of the available queries that
# clients can execute, along with the return type for each. In this
# case, the "allMediablocks" query returns an array of zero or more Mediablocks (defined above).
type Query {
allMediablocks: [Mediablock]
allMedia: [Media]
allUTS: [UTS]
}
`;
My seed file looks like this:
const { PrismaClient } = require('#prisma/client');
const prisma = new PrismaClient();
const mediaData = [
{
UTS: {
create: {
rawText: 'Welcome',
normalisedText: 'welcome',
},
},
Media: {
create: {
url: 'https://www.youtube.com/watch?v=kq9aShH2Kg4',
createdAt: '2022-09-29T12:00:00.000Z',
}
}
}
];
async function main() {
console.log(`Started seeding ...`);
for (const d of mediaData) {
const mediablock = await prisma.Mediablock.create({
data: d,
});
console.log(`Created Mediablock with id: ${mediablock.id}`);
}
console.log(`\nSeeding complete.`);
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
My problem is that when I attempt to query allMediablocks, I can't get any of the UTS or Media data.
query allMediaBlocks {
allMediablocks {
uts {
normalisedText
}
media {
url
}
}
}
// response
{
"data": {
"allMediablocks": [
{
"uts": null,
"media": null
}
]
}
}
I just get null values for both, when in fact, the database (MongoDB) contains references to both of these objects in other tables.
What am I doing wrong? Are my resolvers incorrect?
Is my schema structured incorrectly for MongoDB?
I've fixed it by changing my schema.prisma to be:
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model Mediablock {
id String #id #default(auto()) #map("_id") #db.ObjectId // gen a new, unique id
utsId String #unique #map("uts_id") #db.ObjectId
uts UTS #relation(fields: [utsId], references: [id])
mediaId String #unique #map("media_id") #db.ObjectId
media Media #relation(fields: [mediaId], references: [id])
}
model UTS {
id String #id #default(auto()) #map("_id") #db.ObjectId
rawText String
normalisedText String
createdAt DateTime #default(now())
mediablock Mediablock?
}
// // Mediablocks contain a Video object and connect back to the Mediablock.
// // mediablockId must have #db.ObjectId to match up with Mediablock's id type
model Media {
id String #id #default(auto()) #map("_id") #db.ObjectId
url String
createdAt DateTime #default(now())
mediablock Mediablock?
}
My resolver to be:
const { PrismaClient } = require('#prisma/client');
const prisma = new PrismaClient();
//This resolver retrieves mediabooks from the "mediabooks" array above.
module.exports = {
Query: {
allMediablocks: () => prisma.mediablock.findMany({
include: {
media: true,
uts: true
}
}),
allMedia: () => prisma.media.findMany(),
allUTS: () => prisma.uts.findMany(),
},
};
And my typedefs to be:
module.exports = `
type Mediablock {
id: ID!
uts: UTS
media: Media # can be null when the text is generated first
}
type UTS {
id: ID!
rawText: String!
normalisedText: String!
}
type Media {
id: ID!
url: String!
createdAt: String!
}
# The "Query" type is special: it lists all of the available queries that
# clients can execute, along with the return type for each. In this
# case, the "allMediablocks" query returns an array of zero or more Mediablocks (defined above).
type Query {
allMediablocks: [Mediablock]
allMedia: [Media]
allUTS: [UTS]
}
`;
I also changed the way my seed function works:
const { PrismaClient } = require('#prisma/client');
const prisma = new PrismaClient();
const mediaData = [
{
uts: {
create: {
rawText: 'Welcome',
normalisedText: 'welcome',
createdAt: '2022-09-29T12:00:00.000Z',
},
},
media: {
create: {
url: 'https://www.youtube.com/watch?v=kq9aShH2Kg4',
createdAt: '2022-09-29T12:00:00.000Z',
}
}
}
];
async function main() {
console.log(`Started seeding ...`);
for (const d of mediaData) {
const mediablock = await prisma.Mediablock.create({
data: d,
});
console.log(mediablock);
}
console.log(`\nSeeding complete.`);
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
Now, using the same GraphQL query:
query allMediaBlocks {
allMediablocks {
uts {
normalisedText
}
media {
url
}
}
}
I get the following (desired) response:
{
"data": {
"allMediablocks": [
{
"uts": {
"normalisedText": "welcome"
},
"media": {
"url": "https://www.youtube.com/watch?v=kq9aShH2Kg4"
}
}
]
}
}

why MongoDB returns a CastError when I am trying to delete an Item by id?

I am trying to make the DELETE Rest API method but I get CastError.
The problem is with the id it's of type ObjectID and I made it as a number, even when I chose string I got the same error.
Error
[Nest] 15504 - 22/12/2021, 21:34:11 ERROR [ExceptionsHandler] Cast to ObjectId failed for value "{ id: '61c32ba552a7cec272037b12' }" (type Object) at path "_id" for model "City"
CastError: Cast to ObjectId failed for value "{ id: '61c32ba552a7cec272037b12' }" (type Object) at path "_id" for model "City"
at model.Query.exec (C:\Users\ouss\Desktop\coffeeit-assessment\node_modules\mongoose\lib\query.js:4594:21)
at CitiesService.deleteCity (C:\Users\ouss\Desktop\coffeeit-assessment\src\cities\cities.service.ts:46:64)
at CitiesController.deleteCity (C:\Users\ouss\Desktop\coffeeit-assessment\src\cities\cities.controller.ts:25:31)
at C:\Users\ouss\Desktop\coffeeit-assessment\node_modules\#nestjs\core\router\router-execution-context.js:38:29
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at C:\Users\ouss\Desktop\coffeeit-assessment\node_modules\#nestjs\core\router\router-execution-context.js:46:28
at C:\Users\ouss\Desktop\coffeeit-assessment\node_modules\#nestjs\core\router\router-proxy.js:9:17
cities.service.ts
#Delete(':id')
async deleteCity(id) {
const result = await this.cityModel.deleteOne({ _id: id }).exec();
if (!result) {
throw new NotFoundException('Could not find city.');
}
}
cities.controller.ts
#Delete(':id')
deleteCity(#Param() id: number) {
return this.citiesService.deleteCity(id);
}
city.model.ts
import * as mongoose from 'mongoose';
export const CitySchema = new mongoose.Schema({
name: String,
weather: mongoose.SchemaTypes.Mixed,
});
export interface City {
id: number;
name: string;
weather: mongoose.Schema.Types.Mixed;
}
city.entity.ts
import { BaseEntity, Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
#Entity()
export class City extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#Column()
weather: any;
}
cities.service.ts
import { ObjectId } from 'mongodb';
...
#Delete(':id')
async deleteCity(id) {
const cityId = new ObjectId(id); // Cast id to MongoDB Object id
const result = await this.cityModel.deleteOne({ _id: cityId }).exec();
if (!result) {
throw new NotFoundException('Could not find city.');
}
}

Unknown argument error when creating record

I'm encountering some interesting behaviour when using Prisma ORM. It is related to Prisma's generated types, and I've been skimming the docs trying to find out more, but there doesn't seem to be much info about generated types in there (please correct me if I'm mistaken). Here's the behaviour:
Say I have a model with two 1-1 relations (Profile in the example below):
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id Int #id #default(autoincrement())
name String
profile Profile?
}
model Profile {
id Int #id #default(autoincrement())
name String
userId Int?
user User? #relation(fields: [userId], references: [id])
photoId Int?
photo Photo? #relation(fields: [photoId], references: [id])
}
model Photo {
id Int #id #default(autoincrement())
url String
profile Profile?
}
The following code works when creating a new profile:
const user = await prisma.user.create({ data: { name: "TestUser" } });
const profile = await prisma.profile.create({
data: {
name: "TestProfile",
user: { connect: { id: user.id } },
photo: { create: { url: "http://example.com/img" } },
},
});
... but this fails with an error:
const user = await prisma.user.create({ data: { name: "TestUser" } });
const profile = await prisma.profile.create({
data: {
name: "TestProfile",
userId: user.id,
photo: { create: { url: "http://example.com/img" } },
},
});
The error is:
Unknown arg userId in data.userId for type ProfileCreateInput. Did you mean user? Available args:
type ProfileCreateInput {
  name: String
  user?: UserCreateNestedOneWithoutProfileInput
  photo?: PhotoCreateNestedOneWithoutProfileInput
}
Why is the second create-profile code invalid?
Prisma essentially generates two type definitions for a create query. This is implemented with a XOR type, which ensures that only one definition out of two is fully specified and passed to the query:
export type ProfileCreateArgs = {
/* ... */
data: XOR<ProfileCreateInput, ProfileUncheckedCreateInput>;
}
The definitions are called checked and unchecked, the former using nested fields and the latter using raw ids:
export type ProfileCreateInput = {
id?: number;
/* ... */
user?: UserCreateNestedOneWithoutProfileInput;
photo?: PhotoCreateNestedOneWithoutProfileInput;
}
export type ProfileUncheckedCreateInput = {
id?: number;
/* ... */
userId?: number;
photoId?: number;
}
Which basically means that you either provide all references as connect, create etc. relations (checked) or as raw ids (unchecked). You cannot mix the styles, this is not supported.