PRISMA: How can i select only first string from string array - node.js

I'm looking for solution to taking exact element of String Array in Prisma ORM, in my situation, I want to take only first element of paragraphs array to render short article description on the front.
Thats my article model
model articles {
id BigInt #id #default(autoincrement())
articleId Int #unique
scrapedAt DateTime #default(now())
timeString String
time BigInt
title String
url String
img String
paragraphs String[]
}

Assuming we create articles like the code below
const result = await prisma.articles.create({
data:{
articleId: 1,
timeString: "25082022",
time: 25082022,
title: "First Article title",
url: "First Url",
img: "Image URL",
paragraphs: ["First Paragraph for article", "second paragraph"]
}
})
Then we can query for the paragraphs and pick the first one from the result set
const result = await prisma.articles.findFirst({
where:{
id: 1n
},
select:{
paragraphs: true
}
})
console.log(result.paragraphs[0])
The query returns the result in this form
{ paragraphs: [ 'First Paragrah for article', 'second paragraph' ] }
Then the result of logging result.paragraphs[0] is
Output
First Paragraph for article

Related

Prisma ORM | MongoDB - how to group documents by mutiple attributes and list the rest of them

I'm developing a quite simple backend application with Express, using Prisma ORM to connect to a MongoDB database.
The events collection is filled with documents such as:
{
"_id": string,
"class_code": string
"class_type": string,
"created_by": string,
"end_period": date,
"end_time": time,
"has_to_be_allocated": boolean
"pendings": int,
"preferences": {
"accessibility": boolean
"air_conditioning": boolean,
"building": string,
"projector": boolean
},
"start_period": date,
"start_time": time,
"subject_code": string,
"subject_name": stirng,
"subscribers": int,
"updated_at": timestamp,
"vacancies": int,
"week_day": string,
"building": string,
"classroom": string
}
My prisma schema is:
type Preferences {
accessibility Boolean?
air_conditioning Boolean?
building String?
projector Boolean?
}
model events {
id String #id #default(auto()) #map("_id") #db.ObjectId
class_code String
subject_code String
subject_name String
week_day String
class_type String
start_period String
end_period String
start_time String
end_time String
has_to_be_allocated Boolean
pendings Int
subscribers Int
vacancies Int
created_by String
updated_at String
preferences Preferences?
professor String?
classroom String?
building String?
}
Multiple different documents could have the same class_code and subject_code, but different week_day, start_time, end_time, building and classroom attributes.
My intention is to perform a single query so that I end up with a list of objects like such:
{
"subject_name":"Subject name",
"subject_code":"Subject code",
"class_code":"1",
"professor":"professor name",
"start_period":"2023-03-13",
"end_period":"2023-07-15",
"schedule":[
{
"id":"1",
"week_day":"monday",
"start_time":"09:20",
"end_time":"11:00",
"building":"building 1",
"classroom":"C2-03"
},
{
"id":"2",
"week_day":"thursday",
"start_time":"07:30",
"end_time":"09:10",
"building":"building 2",
"classroom":"C2-08"
},
{
"id":"3",
"week_day":"friday",
"start_time":"07:30",
"end_time":"09:10",
"building":"building 3",
"classroom":"C2-04"
}
]
}
That is, I want to group the documents by subject_code and class_code simultaneously, while listing the rest of the differing information between the documents as schedule.
I could always fetch all documents and algorithmically create the object I need, but that would be rather inefficient (and lame).
Any thoughts on how to perform such task? I've been playing around with Prisma's groupBy API but without any success - needless to say, I'm new to it.
So far all I've got is a route which filters the database by subject_code and class_code, and that works fine:
const classInfo = await prisma.events.findMany({
where: {
subject_code:
equals: subjectCode as string,
},
class_code: {
endsWith: fullClassCode,
},
},
});
I then map the retrieved object to the format I need:
const classDetail = {
subjectName: classInfo?.[0]?.subject_name,
subjectCode: classInfo?.[0]?.subject_code,
classCode: getAbbreviatedClassCode(classInfo?.[0]?.class_code),
professor: classInfo?.[0]?.professor,
startPeriod: classInfo?.[0]?.start_period,
endPeriod: classInfo?.[0]?.end_period,
schedule: classInfo.map((event: Event) => ({
id: event?.id,
weekDay: mapWeekDays(event?.week_day),
startTime: event?.start_time,
endTime: event?.end_time,
building: event?.building,
classroom: event?.classroom,
})),
};
What I need is to list all combinations of subject_code and class_code while obtaining objects like the one I mentioned above.
Ok I am no expert in prisma or mongodb but you can try the following (If this basic query works, just modify it to include the additional fields):
const agg = [
{
'$group': {
'_id': {
'class_code': '$class_code',
'subject_code': '$subject_code'
},
'schedule': {
'$push': {
'week_day': '$week_day',
'start_time': '$start_time'
}
}
}
}
]
const result = await prisma.events.aggregateRaw({
pipeline: agg,
});
References:
https://www.mongodb.com/docs/manual/reference/operator/update/push/
https://www.mongodb.com/docs/manual/reference/operator/aggregation/group/#pivot-data
What does your events prisma schema look like? (IE, how is it defined in the schema.prisma file?
Also, is the schedule a separate collection or are these entries simply embedded documents?

Replace name and return an object

We need to keep track of the school students, but the data we currently have combines the students first and last names into a single name. You have been asked to separate the names to make the data easier to work with.
The makeStudentList function takes an object with a name property whose value will be a string consisting of a first name and a last name, separated by a space. The function should return an object.
The function should remove the name property, replace it with firstName and lastName properties, as shown in the examples below.
Examples:
makeStudentList({ name: "Hannah Fry", age: 4 })
// should return { firstName: "Hannah", lastName: "Fry", age: 4 }
makeGuestList({ name: "Paul Erdős", age: 6 })
// should return { firstName: "Paul", lastName: "Erdős", age: 6 }
function makeStudentList(student) {
const [firstName, lastName] = student.name.split(" ");
delete student.name;
student.firstName = firstName;
student.lastName = lastName;
return student;
} // should return { firstName: "Hannah", lastName: "Fry", age: 4 }
let response = makeStudentList({ name: "Hannah Fry", age: 4 });
const p = document.querySelector('p');
p.append(JSON.stringify(response));
<p></p>
def makeStudentList(name,age):
Name=name.split(" ")
return {"FirstName":Name[0],"lastName":Name[1],"Age":age}
makeStudentList("Hannah Fry",4)
Here you go, lemme know if you need any sort of explanation, cheers:)

How do insert data into this schema?

Below is my prisma schema
model Allegations {
allegation_id String #id #db.VarChar(200)
faculty String? #db.VarChar(200)
department String? #db.VarChar(200)
course String? #db.VarChar(200)
instructor String? #db.VarChar(200)
instructorEmail String? #db.VarChar(200)
instructorPh String? #db.VarChar(200)
details String? #db.VarChar(200)
allegationDate DateTime? #db.DateTime(0)
violationDate DateTime? #db.DateTime(0)
Students Students[]
}
model Students {
id String #id #db.VarChar(200)
student_name String? #db.VarChar(200)
banner String? #db.VarChar(200)
allegation_id String? #db.VarChar(200)
Allegations Allegations? #relation(fields: [allegation_id], references: [allegation_id], onDelete: Restrict, onUpdate: Restrict, map: "Students_ibfk_1")
##index([allegation_id], map: "allegation_id")
}
So far I got his but getting errors. I also tried inserting seperately into allegations and students, but the insert in students doesn't go through.
prisma.allegations.create({
data: {
allegation_id:key,
faculty: Faculty,
department: Department,
course: Course,
instructor: Instructor,
instructorPh: PhoneNumber,
instructorEmail: InstructorEmail,
details: Details,
allegationDate: date,
violationDate: OffenceDate,
Students:{
create:{
student_name: 'kn',
banner: '555555'
},
}
}
});
Modifying your code snippet slightly, I was able to correctly insert a record into the database. Also, you have to specify the student ID because you do not have the #default attribute on the Student schema. Find the modified code below
const allegation = await prisma.allegations.create({
data: {
allegation_id:"1",
faculty: "Science",
department: "Biochemistry",
course: "BCH101",
instructor: "John Doe",
instructorPh: "+231345678",
instructorEmail: "johndoe#test.com",
details: "some details",
allegationDate: new Date('2022','07', '31'),
violationDate: new Date('2022','08', '01'),
Students:{
create:{
id: 'std1',
student_name: 'Test Student',
banner: '555555'
},
}
}
})

I'm using node/express and the pg library to communicate with PostgreSQL. When my model returns data, the properties are lowercased. Why?

The basic question, is why is it changing the property job.companyHandle to job.companyhandle?
In my Job model, I have this function:
static async create({ title, salary, equity, companyHandle }) {
const duplicateCheck = await db.query(
`SELECT title
FROM jobs
WHERE title=$1 AND company_handle=$2`,
[title, companyHandle]);
if (duplicateCheck.rows[0])
throw new BadRequestError(`Duplicate job: ${title} at ${companyHandle}`);
const result = await db.query(
`INSERT INTO jobs
(title, salary, equity, company_handle)
VALUES ($1, $2, $3, $4)
RETURNING id, title, salary, equity, company_handle AS companyHandle`,
[
title,
salary,
equity,
companyHandle
],
);
const job = result.rows[0];
return job;
}
My jest testing code for that function looks like this:
describe("create", function () {
const newJob = {
title: "NJ1",
salary: 50000,
equity: "0.45",
companyHandle: "c3"
};
test("works", async function () {
let job = await Job.create(newJob);
expect(job).toEqual({ ...newJob, id: expect.any(Number) });
const result = await db.query(
`SELECT id, title, salary, equity, company_handle AS companyHandle
FROM jobs
WHERE title = 'NJ1'`);
expect(result.rows).toEqual([
{
id: expect.any(Number),
title: "NJ1",
salary: 50000,
equity: "0.45",
companyHandle: "c3"
},
]);
});
... another test ...
});
So I've tried removing the AS companyHandle from the return statement and adding
job.companyHandle = job.company_handle;
delete job.company_handle;
into the model right before the return. In some of the other tests, this returns the proper companyHandle property, but in the first test case, it's still coming back as companyhandle. I don't understand why it's returning a lowercase.
A quick view of the jest results:
create › works
expect(received).toEqual(expected) // deep equality
- Expected - 1
+ Received + 1
## -1,8 +1,8 ##
Array [
Object {
- "companyHandle": "c3",
+ "companyhandle": "c3",
"equity": "0.45",
"id": Any<Number>,
"salary": 50000,
"title": "NJ1",
},
Also, I know a bunch of this code probably isn't necessary, but I've seen too many posts without enough context, so I decided to err on the side of over sharing.
As was mentioned in the comments, I made the mistake of not double quoting my identifiers.
I was too focused in on one case, and missed all of the other returns where I had not double quoted.
Thank you #Crontab and #Adrian Klaver

match all if the user doesn't specify the field value MongoDB

I am building an API where I have several fields that are optional in my get request. So I want MongoDB to match all values for those optional fields if the user does not specify it. I have come up with this solution:
db.collection(expenses_collection).find(username: username, category: {$regex:"/" + category + "/"}, payment_type: {$regex:"/" + payment_type + "/"}})
Where if category and payment_type are not specified by the user I set them to ".*":
const {category=".*", payment_type=".*"} = req.query;
However, mongodb is still not matching any data. Any help is appreciated. Thanks a lot.
The issue is with your regex string. To match any string value, you have to use this pattern (this matches any string): (.*?)
Consider input documents:
{ _id: 1, name: "John", category: "cat 1", payment_type: "cash" },
{ _id: 2, name: "Jane", category: "cat 2", payment_type: "credit card" }
Usage to match any category field value:
let categoryStr = /(.*?)/
db.exp.find( { category: categoryStr } )
The query returns all documents.
So, in your application for the category value not specified the code can be like this:
if (category is empty or null) { // category not specified by user
categoryStr = /(.*?)/
}
Similarly, for the payment_type field also.
Then query would be:
db.exp.find( {
username: usernameStr,
category: categoryStr,
payment_type: paymentStr
} )
NOTE: The code tests fine with MongoDB NodeJS driver APIs.
Isn't this what exists is made for?
{category: { $exists: true }, payment_type: { $exists: true }}

Resources