我正在开发一个具有Firebase后端的应用程序。在注册过程中,我想让新用户看到他们中的哪些联系人已将其添加为应用程序。因此,基本上,请使用电话号码将用户与联系人匹配。
查询数据库以查找用户时,我的性能非常头痛。由于Firestore不支持OR查询,因此我针对每个电话号码运行两个查询(一个查询国家/地区格式,另一个查询国际格式),如果有返回文档,请将该文档设置为找到的用户:
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和许多其他应用程序都具有此功能,并且可以立即加载。我并没有试图达到完美的水平,但是必须有一些更好的方法……任何帮助/建议都将不胜感激。