Struggling with establishing connection logic between two database tables using Prisma and JavaScript

I'm facing a perplexing logic problem that is eluding my understanding. Within the context of using next-connect, I have a function designed to update an entry in the database:

  .put(async (req, res) => {
    const data = req.body;
    const { dob, roles, cases } = data ?? {};
    const convertedDob = dob ? new Date(dob) : null;

    const roleIds = roles?.map((role: Role) => {
      return { id: role.id };
    });

    const caseIds = cases?.map((_case: Case) => {
      return { id: _case.id };
    });

    data.dob = convertedDob;
    delete data.roles;
    delete data.formData;

    const user = await getUserDataFromSession(req, res);
    throwIfNoCurrentTeam(user?.currentTeam);

    try {
      const person: Person = await prisma.person.update({
        where: { id: data.id },
        data: {
          ...data,
          roles: { connect: roleIds },
          cases: { connect: caseIds },
        },
      });

      if (person && person.linkedIds) {
        // get linkedId arrays of all people linked to this person
        const associatedPeopleIdArrays = await prisma.$transaction(
          person.linkedIds.map((id) =>
            prisma.person.findUnique({
              where: { id },
              select: { id: true, linkedIds: true },
            }),
          ),
        );

        const backLinkArray = associatedPeopleIdArrays.map((linkedPerson) => {
          const linkedPersonIds = linkedPerson?.linkedIds;
          const linkedPersonOwnId = linkedPerson?.id;

          // if the array of linkedIds already includes the person we are back-linking, enter next check
          if (linkedPersonIds?.includes(person.id)) {
            // if they both include each other, do nothing
            if (person.linkedIds.includes(linkedPersonOwnId as string)) {
              return { id: linkedPersonOwnId, linkedIds: linkedPersonIds };
            }
            // if linkedPersonIds includes person.id but person.linkedIds does not include linkedPersonOwnId, remove the relationship
            return { id: linkedPersonOwnId, linkedIds: linkedPersonIds.filter((id) => id !== person.id) };
            // else add the current person's id to each person's array that we are back-linking
          } else {
            return {
              id: linkedPersonOwnId,
              linkedIds: linkedPersonIds ? [...linkedPersonIds, person.id] : [person.id],
            };
          }
        });

        // write the new linkedId array to each associated person
        await prisma.$transaction(
          backLinkArray.map((linkedPerson) =>
            prisma.person.update({
              where: { id: linkedPerson?.id },
              data: {
                linkedIds: linkedPerson?.linkedIds,
              },
            }),
          ),
        );
      }

      return res.status(200).json({ updated: person });
    } catch (err: any) {
      console.log({ err });
      handleApiError('Failed to update person', 500, err);
    }
  });

In attempting to unravel this puzzle, I have included comments throughout the code to aid comprehension. While logs have been strategically placed to shed light on the process, the challenge lies within the intricate if/else logic.

The function effectively establishes relationships between individuals. When adding an id to one person's linkedIds array, the same id should be added to the associated person's array as well.

However, there exists a need for additional criteria to sever a relationship when an id is removed from a person's linkedIds. This aspect seems to be faltering. The issue arises after entering the statement

if (linkedPersonIds?.includes(person.id))
, followed by invariably executing the subsequent condition
if (person.linkedIds.includes(linkedPersonOwnId as string))
.

It was anticipated that deleting an id from the linkedIds array would yield a false outcome, yet it persistently returns true, impeding the deletion of the relationship. What am I overlooking? Where has my understanding lapsed?

Pardon the chaotic presentation, and I trust you can navigate through this labyrinthine scenario!

Answer №1

It became apparent to me what the main issue was... when constructing the associatedPeopleArrays, it failed to include the recently deleted id in the backLinkArray. This meant that there would never be a validation for that particular id!

Therefore, I realized the necessity to retrieve the previous version of the linkedIds array before any updates were made. This required adjustments on the frontend to ensure this information was transmitted alongside the updated data.

This allowed me to compare the old linkedIds with the new ones and identify any discrepancies. While I admit my code may seem lengthy and intricately detailed, this solution proved effective!

      if (person?.linkedIds || initialLinkedIds) {

        // ADD RELATIONSHIPS
        // obtain arrays of linkedIds for all newly associated people with this person
        const newlyAssociatedPeopleIdArrays = await prisma.$transaction(
          person.linkedIds.map((id: string) =>
            prisma.person.findUnique({
              where: { id },
              select: { id: true, linkedIds: true },
            }),
          ),
        );

        // populate the associated peoples' arrays with the person that just added them
        const addRelationshipArray = newlyAssociatedPeopleIdArrays?.map((linkedPerson) => {
          const linkedPersonIds = linkedPerson?.linkedIds;
          const linkedPersonOwnId = linkedPerson?.id;

          if (!linkedPersonIds?.includes(person.id)) {
            return { id: linkedPersonOwnId, linkedIds: [...linkedPersonIds, person.id] };
          }

          return linkedPerson;
        });

        // REMOVE RELATIONSHIPS
        // find the difference between the old linkedIds and the current linkedIds
        const removedIds = initialLinkedIds.filter((id: string) => !person.linkedIds.includes(id));

        // obtain linkedId arrays for each id that has been removed
        const newlyRemovedPeopleIdArrays = await prisma.$transaction(
          removedIds.map((id: string) =>
            prisma.person.findUnique({
              where: { id },
              select: { id: true, linkedIds: true },
            }),
          ),
        );

        // iterate over these linkedId arrays and remove the current person
        const removeRelationshipArray = newlyRemovedPeopleIdArrays.map((unlinkedPerson) => ({
          ...unlinkedPerson,
          linkedIds: unlinkedPerson.linkedIds.filter((id: string) => id !== person.id),
        }));

        // merge the two relationship arrays
        const combinedUpdateArray = [...removeRelationshipArray, ...addRelationshipArray];

        // update the database with these new arrays
        await prisma.$transaction(
          combinedUpdateArray.map((linkedPerson) =>
            prisma.person.update({
              where: { id: linkedPerson?.id },
              data: {
                linkedIds: linkedPerson?.linkedIds,
              },
            }),
          ),
        );
      }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error: Attempting to access the properties `line_items.amount`, `line_items.currency`, `line_items.name`, `line_items.description`, or `line_items` is not allowed

Hi there, I'm currently working on creating an Amazon-inspired platform and I've encountered an error while trying to integrate Stripe with the project. Can anyone provide some assistance? You can refer to the video tutorial I'm using by fol ...

Tips on employing useState within useEffect?

Attempting to refactor my component from react.component to hooks has been a bit challenging. I am struggling to properly utilize the state variable offsetTop. It seems like the value is not being set when needed. In my first attempt: const [offsetTop, se ...

Issue: The useHref() function is restricted to usage within a <Router> component. This error occurred within the register.js file

Hey there, I'm currently working on a reactjs app and everything is running smoothly with the routes except for the register user function which is throwing an error: Error: useHref() may be used only in the context of a component. I am utilizing fire ...

Incorporating a user ID (foreign key) into a MySQL table using NextJS and Prisma

Currently, I am in the process of developing an online recipe platform that allows users to log in and share their recipes. The technology stack I am using includes NextJS, Prisma, and MySQL DB. User authentication is handled with NextAuth and a credential ...

Guidelines for creating a routing for a child component using Angular

Seeking assistance with setting up routing in an Angular application. I have a main component called public.component, and the auth.component component is inserted from the child module Auth.module using the selector. How can I configure the routing for th ...

Tips on implementing live updates in Firebase without the need for reloading the page

After a user changes their profile picture, the update does not appear until they refresh the page. Here is the code snippet causing this issue: const handleProfile = async (e: any) => { const file = e.target.files[0] const storageRef = firebase ...

Dealing with Scoping Problems in a Typescript d3 Update Tutorial

I'm facing challenges trying to implement the provided bl.ocks example in Typescript (using Angular). This is my implementation in TypeScript: StackBlitz Could anyone offer insights on what might be causing the issues I'm encountering? My initi ...

Enhanced Autocomplete Feature with Select All Option in MUI

Currently, I am utilizing Material UI (5) and the Autocomplete component with the option for multiselect enabled. In addition, I am implementing the "checkbox" customization as per the MUI documentation. To enhance this further, I am attempting to incorpor ...

Using Sanitize.css to customize Material UI styles

Currently, I am utilizing Next JS (v9.2) along with Material-UI (4.9.0). In my code in the _app.js file, I have imported sanitize.css (v11.0.0). However, I have noticed that when implementing a material-UI outlined text-field, the outline does not appear ...

When attempting to import a schema from a file, an error occurs: ReferenceError - 'MySchema' cannot be accessed before initialization

I have a scenario where I create a schema in one file // Vendor.ts export { ShortVendorSchema }; const ShortVendorSchema = new Schema<TShortVendor>({ defaultVendor: Boolean, companyName: String, vendorId: { type: Schema.Types.ObjectId, ...

How to update an Array<Object> State in ReactJS without causing mutation

In my program, I store an array of objects containing meta information. This is the format for each object. this.state.slotData [{ availability: boolean, id: number, car: { RegistrationNumber : string, ...

Can TypeScript be implemented within nuxt serverMiddleware?

I recently began diving into the world of nuxtjs. When setting up, I opted to use typescript. Initially, everything was running smoothly until I decided to incorporate express in the serverMiddleware. Utilizing the require statement to import express funct ...

I am looking to have the datepicker automatically clear when the reset button is clicked

this code snippet is from my component.ts file resetFilters() { this.date = 0; this.query.startedAt= null; this.query.endedAt=null; this.searchTerm = ''; this.route.params.subscribe((params) => { this.machineId = Numb ...

Generating auto UUIDs in PostgreSQL using TypeORM

Currently, I am in the process of developing a REST API and utilizing TypeORM for data access. While I have been able to use it successfully so far, I am facing an issue regarding setting up a UUID auto-generated primary key on one of my tables. If anyone ...

Feeling lost with the concept of getcontext in js/ts and uncertain about how to navigate through it

Recently, I've been encountering undefined errors in my browser and can't seem to figure out how to resolve them. It seems that the usage of the keyword "this" in JavaScript and even TypeScript is causing quite a bit of confusion for me. Let&apo ...

Error Encountered during Compilation of React TypesIs this okay

Currently, I am working on an MVC project that involves the use of TypeScript. To access the types required for this project, I have also integrated React. To obtain the React types, I performed an npm install --save-dev @types/react (similarly for react-d ...

While validating in my Angular application, I encountered an error stating that no index signature with a parameter of type 'string' was found on type 'AbstractControl[]'

While trying to validate my Angular application, I encountered the following error: src/app/register/register.component.ts:45:39 - error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used ...

Using any random function as a property value in a TypeScript React Component

I am facing a challenge in my React component where I need to define a property that can accept any arbitrary function which returns a value, regardless of the number of arguments it takes. What matters most to me is the return value of the function. Here ...

Can one validate a single route parameter on its own?

Imagine a scenario where the route is structured as follows: companies/{companyId}/departments/{departmentId}/employees How can we validate each of the resource ids (companyId, departmentId) separately? I attempted the following approach, but unfortunate ...

Adjust an IntervalObservable's interval by incorporating a variable

I've encountered an issue with a component that needs to run code at regular intervals without pausing. I'm currently using an IntervalObservable and need to adjust the interval dynamically. While I can change the variable value using the setTime ...