Prevent contact duplicates in custom registration?

Is there any way you can use Wix Code to prevent duplicate contacts (same email) for my custom registration page?

Hello Brett,

Yea here is how to do it:

  1. Get current user email
  2. Query collection you are storing all the contacts in for that email
  3. If query returns something prevent registration(Redirect to another page, show error message, etc…)
  4. If query did not return something, insert into collection normally

Here is a template of how to do it with code:

import wixUsers from 'wix-users';

// ...

let user = wixUsers.currentUser;

user.getEmail()
  .then( (email) => {
    let userEmail = email;      // "user@something.com"
    
    wixData.query('YourCollectionName')
      .eq('emailField', userEmail)
      .find()
      .then((res) => {
          if(res) {
              return console.log('Duplicate user found, returning');
              //add error message to show or redirect here
          }
          //insert to collection here (no duplicate found)
      })
  } );

Hope this helps,
Majd

1 Like

Hi Brett,

Adding to what Majd said, it would be a good idea to put a Hook before insert. Take a look HERE to see how it works.

Best,

Mustafa

1 Like

Thanks for the help, Majd and Mustafa. The detection works, but I just need help with showing an error message. I believe it might just be the brackets.

Here is what I have. It says I have an error on the last line.

let user = wixUsers.currentUser;

user.getEmail()
.then( (email) => {
let userEmail = email; // "user@something.com"

wixData.query('contactInfo')
.eq('#email', userEmail)
.find()
.then((res) => {
if(res) {
return console.log('Duplicate user found, returning');
//add error message to show or redirect here
if ('Duplicate user found, returning') {
$w('#error').show();
$w('#errorText').show();
}

//insert to collection here (no duplicate found)
}
} 
);


Brett,

It would look like this:
PS. Make sure to change .eq(’ emailField ', userEmail) → the emailField value here to your actual database field value.

import wixUsers from 'wix-users';

let user = wixUsers.currentUser;

user.getEmail()
  .then( (email) => {
    let userEmail = email;      // "user@something.com"
    
    wixData.query('YourCollectionName')
      .eq('emailField', userEmail)
      .find()
      .then((res) => {
          if(res) {
              console.log('Duplicate user found, returning');
              //below is error messages to show
               $w('#error').show(); 
               $w('#errorText').show(); 
          }
          //insert to collection here (no duplicate found)
      })
  } );

Hope this helps,
Majd

1 Like

So, I put the code in, but the message does not work. Here is my code:

import wixData from 'wix-data';

let user = wixUsers.currentUser;

user.getEmail()
  .then( (email) => {
 let userEmail = email;      // "user@something.com"
 
    wixData.query('contactInfo')
      .eq('#email', userEmail)
      .find()
      .then((res) => {
 if(res) {
              console.log('Duplicate user found, returning');
 //below is error messages to show
               $w('#error').show();
               $w('#erroBig').show();
               $w('#errorText').show();
               $w('#errorBubble').show();
          }
 else {
              wixData.insert("contactInfo",userEmail)
          }
 //insert to collection here (no duplicate found)
      })
  } );

Hello Brett,

Try following this guide on doing this here: https://www.wix.com/code/home/forum/community-discussion/search-for-duplicate-entires

What may be the problem is that #email is not a field in your database. Go to your collection, click view properties of the email field, and get the fieldValue. This is what should be there instead of #email.

Best,
Majd

1 Like

Hio Brett:

find() will return an array of items that it gets from your .eq() query.

You should test the res.totalCount to see if it is greater than 0 to determine if you have an existing record better yet you should test greater than 1 also as that would be a coding error [;-)] and you would need to figure out how you let duplicates in in the first place.

So I’ve proposed some changes below that use the Promises from these calls more effectively. By returning a function call that returns a Promise you can cascade .then() calls at the same level in your code and terminate the string with a catch for exceptions. You can then use the exception catch for dealing with all errors so when you have a logic error you simply throw and error (exception) which terminates the code flow and jumps you to the catch.

import wixData from 'wix-data';
let user = wixUsers.currentUser;
user.getEmail()
 .then( (email) => {
    let userEmail = email;
    // "user@something.com"
    // ******* Return the query find() and handle the then at the same level 
    // as getEmail. Then use catch foone catch for all errors
    return wixData.query('contactInfo')
     .eq('#email', userEmail)
     .find();
 })
 .then((res) => {
     if(res.totalCount > 1) {
         // Internal Error more than one entry exists
         throw Error('Internal Error - more than one entry exists');
     } else if (res.totalCount === 1) {
          throw Error('Duplicate user found, returning');
     }
     //insert to collection here (no duplicate found) 
     return wixData.insert("contactInfo",userEmail);
 })
 .catch((error) => {
     //below is error messages to show 
     $w('#error').show();   
     $w('#errorBig').show(); 
     $w('#errorText').show(); 
     $w('#errorBubble').show();
     console.log(error);
 } );

Hope this is helpful. At a minimum you need to check the totalCount :slight_smile:

1 Like

Hello, I have built a custom registration page as outlined here: https://support.totallycodable.com/en/article/custom-registration-for-site-login . It works as designed for brand new people and email addresses, however I am having a hard time with duplicate contact entries if someone enters an existing email address.

If a potential member enters an email address that is already in the site contacts and clicks submit, the lightbox stays up for that person as though nothing has happened but the contact is inserted into the wix contacts function anyway, creating a duplicate contact with the same email address and first/last name. It does not however create another site member, which is good.

My biggest concern is the potential member who stays stuck on the custom registration page rather than getting taken to the next location as outlined in the code. Is there a way to insert error messages into this custom registration flow? And, if so, how can I use the code outlined earlier in this thread to make that happen? Does that go inside the lightbox code or in the back-end? Please note, I already have a data.js file in the backend as outlined here to prevent duplicates on profile update: https://codequeen.wixsite.com/membership-dashboard . I am using this create/update profile flow once the user has an account on the site, and this is working well also.

For reference, my code from the custom registration lightbox is as follows:

import wixUsers from ‘wix-users’;
import wixWindow from ‘wix-window’;
import wixLocation from ‘wix-location’;
import wixData from ‘wix-data’;

$w.onReady( function () {

$w("#registerButton").onClick( (event) => { 

let email = $w(“#email”).value;
let password = $w(“#password”).value;
let first = $w(“#firstName”).value;
let last = $w(“#lastName”).value;

wixUsers.register(email, password, {
contactInfo: {
“firstName”: first,
“lastName”: last
}
} )
.then( (result) => {

let resultStatus = result.status;
wixWindow.lightbox.close();
wixLocation.to(“/join-wrcra-2”);
} );
} );

});

Thank you!

I believe that the answers above only show how to search for duplicates, but they do so after the member is already signed up as they use wixUsers.currentuser. The point here is to avoid signing up the users. Also, there’s no need for a custom database, as the email is stored in the members database.
This is how I solved it:

Search for existing email in backend (might make more sense to put this in a hook, but the “add hook” interface does not provide a pre-insert hook for the membersData. I’m not sure whether there’s a reason and whether it’s possible)

// Filename: backend/reg.jsw (web modules need to have a .jsw extension)
import wixUsers from 'wix-users-backend';
import wixData from 'wix-data';

function searchForSignupDuplicateEmails(emailToCheck) {
 let options = {
 "suppressAuth": true,
    };
 return wixData.query("Members/PrivateMembersData")
        .eq("loginEmail", emailToCheck)
        .find(options)
        .then((results) => {
 return results.items.length;
        })
        .catch((err) => {
 return Promise.reject(err);
        });
}

export function doRegistration(email, password, userName) {
 let tryNameLowerCase = userName.toLowerCase();
 return searchForSignupDuplicateEmails(email)
        .then((emailDupeCheckResult) => {
 if (emailDupeCheckResult > 0) {
 return Promise.reject("This email is already in use");
            }
        })
 // else //no duplicate email or username found, proceed to do registration
        .then(() => {
 return wixUsers.register(email, password, {
 "contactInfo": {
 "emails": emails,
 "labels": labels
                }
            })
        })
        .catch((err) => {
 return { "succeeded": false, "returnMessage": err };
        });
}

And here’s code to process that reply and display error messages in the lightbox. Note the names of the $w entities which are likely not the same as yours, and you need to replace with yours. Also, I added error messages in the lightbox which are hidden by default, and only get shown when relevant ($w(‘#emailUsedErrorText’).show() and $w(‘#errorText’).show())

import wixUsers from 'wix-users';
import wixLocation from "wix-location";
import { doRegistration } from 'backend/reg';
import wixWindow from 'wix-window'; //you might not need some of these imports

$w.onReady(function () {
    $w('#submit').onClick(() => {

        doRegistration($w('#email').value, $w('#password').value, $w('#inputUserName').value)
            .then((result) => {
 if (result.succeeded === true) {
                    wixLocation.to("/after-signup-location");
                } else {
 if (result.succeeded === false) {
 if (result.returnMessage === "This email is already in use") {
                            $w('#emailUsedErrorText').show();
                        } else {
                            $w('#errorText').show();
                        }
                    } else {
                        $w('#errorText').show();
                    }
                }
            })
            .catch((err) => {
                 $w('#errorText').show();
            });
    });
});
1 Like