Быстрый поиск пользователей по номеру телефона с бэкэндом Firebase - PullRequest
0 голосов
/ 03 сентября 2018

Я работаю над приложением с бэкэндом Firebase. Во время регистрации я хотел бы позволить новым пользователям видеть, какие из их контактов уже есть в приложении, чтобы добавить их в друзья. Поэтому, в основном, используйте телефонные номера для сопоставления пользователей с контактами.

У меня сильная головная боль при работе с базой данных для поиска пользователей. Поскольку Firestore не поддерживает ИЛИ-запросы, я запускаю два запроса на номер телефона (один для проверки национального формата, другой для международного формата), и если какой-либо из них возвращает документ, задайте этот документ в качестве найденного пользователя:

findUserByPhoneNumber = (number, callback) => {

  //utility function to, well, sanitize phone numbers
  sanitizeNumber = (str) => {
    if (str) {
      var num = str.match(/\d/g);
      num = num.join("");
      return num;
    } else {
      return null
    }
  }

  var foundUser = null

  Promise.all([
    usersRef.where('phoneNumbers.nationalFormat', '==', sanitizeNumber(number)).get()
      .then(snapshot => {
        if (snapshot.docs.length > 0 && snapshot.docs[0].data()) {
          // console.log('nationalFormat result: ', snapshot.docs[0]);
          foundUser = snapshot.docs[0].data()
        }
        return foundUser
      }),
    usersRef.where('phoneNumbers.internationalFormat', '==', sanitizeNumber(number)).get()
      .then(snapshot => {
        if (snapshot.docs.length > 0 && snapshot.docs[0].data()) {
          // console.log('internationalFormat result: ', snapshot.docs[0]);
          foundUser = snapshot.docs[0].data()
        }
        return foundUser
      })
  ])
  .then(results => {
    res = results.filter(el => { return el != null })
    if (results.length > 0) {
      callback(res[0])
    }
  })
}

findUserByPhoneNumber работает для каждого контакта в цикле. При тестировании на моем телефоне с 205 контактами весь процесс занимает около 30 секунд, что примерно на 29 секунд дольше, чем мне бы хотелось, особенно если учесть, что в тестовой базе данных всего 8 записей ...

getContacts = () => {

  getCs = () => {
    // Declare arrays
    const contactsWithAccount = []
    const contactsWithNoAccount = []

    // Get contacts from user's phone
    Contacts.getAll((err, contacts) => {
      if (err) throw err

      // For each contact, iterate
      for (var i = 0; i < contacts.length; i++) {
        const item = contacts[i]

        if (item.phoneNumbers && item.phoneNumbers.length > 0) {
          const phone = item.phoneNumbers[0].number

          // If the sanitized phone number is different from the current user's phone number (saved in DB), run the following logic
          if (this.state.user.phoneNumbers.nationalFormat != sanitizeNumber(phone)
            && this.state.user.phoneNumbers.internationalFormat != sanitizeNumber(phone)
          ) {

            findUserByPhoneNumber(phone, (fu) => {
              contactObject = {
                key: item.recordID,
                name: item.givenName,
                normalizedName: item.givenName.toLowerCase(),
                phoneNumber: phone,
                user: this.state.user,
                hasAccount: null,
                friendId: null,
                isFriend: null
              }

              const foundUser = fu

              // if found user, push in contactsWithAccount, otherwise push in contactsWithNoAccount
              if (foundUser && foundUser._id != this.state.user._id) {
                contactObject.hasAccount = true
                contactObject.friendId = foundUser._id
                if (this.state.user.friends && this.state.user.friends.includes(foundUser._id)) {
                  contactObject.isFriend = true
                }
                contactsWithAccount.push(contactObject)
              }
              else {
                contactsWithNoAccount.push(contactObject)
              }

              // if the two arrays are filled up, run the callback
              // NOTE_1: we use the two lengths +1 to account for the current
              //         user's document that we skip and dont add to any of the arrays
              // NOTE_2: this bizare method was the only way to handle the results
              //         coming in asynchronously
              if (contactsWithAccount.length + contactsWithNoAccount.length + 1 == contacts.length) {
                console.log('finished');
                sortCs(contactsWithAccount, contactsWithNoAccount)
              }
            })
          }
        }
      }

    })

  }

  // sorts the two arrays alphabetically
  sortCs = (withAccount, withNoAccount) => {
    compare = (a,b) => {
      if (a.name < b.name)
        return -1;
      if (a.name > b.name)
        return 1;
      return 0;
    }
    withAccount.sort(compare)
    withNoAccount.sort(compare)
    this.setState({ withAccount, withNoAccount })
  }

  // unleash the monster
  getCs(sortCs)
}

Я уверен, что процесс можно оптимизировать различными способами. Может быть:

  • другая структура базы данных
  • объединение всех запросов в один
  • лучше использовать асинхронный
  • запуск процесса на более раннем этапе в потоке регистрации

WhatsApp, HouseParty и множество других приложений имеют эту функцию и загружаются мгновенно. Я пока не пытаюсь достичь этого уровня совершенства, но должен быть какой-то лучший способ ... Любая помощь / предложения будут с благодарностью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...