Map over collection to upsert into the database. How to batch upsert?

6.7k Views Asked by At

Say, I have a data structure coming in from the frontend as follows:

const userData = [
  {
    id: 11223,
    bb: [
      {
        id: 12,
      },
      {
        id: 34,
        bbb: "bbb",
      },
    ],
  },
  {
    id:4234,
    ...
  },
];

Because, none/ some/ all of the data may already be in the database, here is what I have come up with:

const collection = [];
for (let i = 0; i < userData.length; i++) {
  const cur = userData[i];
  const subCur = cur.bb;
  const updatedCur = await db.cur.upsert({
      where: {
        id : cur.id
      },
      update: {
        ...
      },
      create: {
        ...
      },
    })
  );
  collection.push(updatedCur);
  for (let j = 0; j < subCur.length; j++) {
    const latest = subCur[j];
    await db.subcur.upsert({
      where: {
        id : latest.id
      },
      update: {
        ...
      },
      create: {
        ...
      },
    });
  }
}

To summarise, I am mapping over the userData & upsert each object one by one. Within the loop, I map over the child collections & upsert them in the db.

My concern is that I am making a lot of entries into the Db this way. Is this the best way to do this?

Aside: I previously, tried to do multiple inserts within the upsert, however, I got stuck with the update section as to my knowledge, we cannot upsert multiple records within the update nested within upsert. Is this correct?

UPDATE:

As requested by Ryan, here is what the Schema looks like:

model Cur {
  id      Int,
  subCur  SubCur[]
  ...
}

model SubCur {
  id      Int,
  cur     Cur  @relation(fields: [curId], references : [id])
  curId   Int
  ...
}

To summarise, there are many models like 'SubCur' with 1-n relation with 'Cur' model. As the 'UserData' payload, may have some data that is new, some that is update for existing data already in Db, I was curious, whats the best approach to upsert the data into the db. To be specific, do I have to insert each one, one at a time?

1

There are 1 best solutions below

0
On BEST ANSWER

I assumed your schema to be this:

model Cur {
  id Int @id
}

model Subcur {
  id  Int     @id
  bbb String?
}

And here's a better version:

const collection = await prisma.$transaction(
    userData.map(cur =>
      prisma.cur.upsert({
        where: { id: cur.id },
        update: {},
        create: { id: cur.id },
      })
    )
  )

  await prisma.$transaction(
    userData
      .flatMap(cur => cur.bb)
      .map(latest =>
        prisma.subcur.upsert({
          where: {
            id: latest.id,
          },
          update: {
            bbb: latest.bbb,
          },
          create: {
            id: latest.id,
            bbb: latest.bbb,
          },
        })
      )
  )