Nozbe / WatermelonDB

🍉 Reactive & asynchronous database for powerful React and React Native apps ⚡️
https://watermelondb.dev
MIT License
10.62k stars 600 forks source link

Any recommended way of preventing duplicate entries while inserting batch records #36

Closed Kabangi closed 5 years ago

Kabangi commented 6 years ago

At the moment am using this custom functions to prevent duplicates. This works great but not sure if this is the recommended way of doing it. I wish there was a functionality such as firstOrCreate that either modifies properties or create a fresh record.

import { Q } from '@nozbe/watermelondb';

async function getExistingContactsBySids(db, contactIds: array<string>) {
  return await db.collections
    .get('contacts')
    .query(Q.where('sid', Q.oneOf(contactIds)))
    .fetch();
}

function makeContact(db, c, existingContacts) {
  const contactToUpdate = existingContacts.find(exC => exC.sid == c.id);
  if (contactToUpdate) {
    return contactToUpdate.prepareUpdate(contact =>
      transformContactForStore(contact, c)
    );
  }

  return db.collections
    .get('contacts')
    .prepareCreate(contact => transformContactForStore(contact, c));
}

function transformContactForStore(contact, c) {
  contact.sid = c.id;
  contact.username = c.username;
  contact.email = c.email;
  contact.firstName = c.first_name;
  contact.middleName = c.middle_name;
  contact.lastName = c.last_name;
}

export async function createLocalContactsFromAPI(db, contacts) {
  const contactIds = contacts.reduce((pv, cv) => {
    pv.push(cv.id);
    return pv;
  }, []);

  const existingContacts = await getExistingContactsBySids(db, contactIds);

  const finalContacts = contacts.map(c => makeContact(db, c, existingContacts));
  return await db.batch(...finalContacts);
}
radex commented 6 years ago

Hey @Kabangi.

Your use case is valid, and you're right, it should be easier to do.

Your solution (find by id oneOf(ids...), then update or create) is, I think, the best you can do at this moment.

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.