如何加快此 Firestore 查询循环的性能?正在将 phone 联系人列表与 Firestore 数据库进行匹配
How can I speed up performance of this Firestore query loop? Comparing phone contact list to Firestore database for matches
我正在将用户 phone 中的联系人电子邮件列表与我的 Firestore 数据库中的用户电子邮件列表进行比较,然后创建新的 "contactsInApp" 列表。
首先,我从 firestore 数据库中获取了整个用户集合。然后为每个用户创建一个 forEach 循环,检查我的 phone 联系人列表中的每个联系人是否匹配。如果有匹配项,它会创建一个 "androidContactsInApp" 的新列表。当有少量用户时它工作正常,但当我对 5,000 名用户进行测试时,它需要更长的时间 - 大约 30 秒。我认为 firestore 应该可以很好地扩展,所以想知道我的代码是否有问题。
这是我的代码:
fsDB.collection("users")
.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
for (DocumentSnapshot document : documentSnapshots) {
String userEmail = document.get("email").toString();
for (UserInfoForRequest android_contact: arrayListAndroidContacts) {
String isEmailInDatabase = android_contact.getUserEmail();
String trimmedEmail = isEmailInDatabase.trim();
if (userEmail.equals(trimmedEmail)) {
String userID = document.getId();
UserInfoForRequest android_contact2 = new UserInfoForRequest();
android_contact2.setUserName(document.get("username").toString());
android_contact2.setUserEmail(userEmail);
android_contact2.setCurrentUID(currentUID);
android_contact2.setContactsUID(userID);
arrayListAndroidContactsInApp.add(android_contact2);
}
}
}
adapterWithApp.notifyDataSetChanged();
adapterNoApp.notifyDataSetChanged();
}
});
我也试过反转循环。这样做,我得到了我的 phone 联系人列表中的每个联系人,并为每个 phone 联系人执行查询。这意味着我没有下载整个用户集合。这种方法要慢得多——慢得多。我认为那是因为我执行单独的、单独的查询。这是我的代码:
for (final UserInfoForRequest android_contact: arrayListAndroidContacts) {
String contactsEmail = android_contact.getUserEmail();
String trimmedEmail = contactsEmail.trim();
fsDB.collection("users").whereEqualTo("email", trimmedEmail).get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
if (documentSnapshots.isEmpty()) {
Log.d("FOUNDEMAIL", " document is empty ");
}
else {
List list = documentSnapshots.getDocuments();
DocumentSnapshot doc = (DocumentSnapshot) list.get(0);
UserInfoForRequest android_contact2 = new UserInfoForRequest();
android_contact2.setUserName(doc.get("username").toString());
android_contact2.setUserEmail(doc.get("email").toString());
android_contact2.setCurrentUID(currentUID);
android_contact2.setContactsUID(doc.getId());
arrayListAndroidContactsInApp.add(android_contact2);
adapterWithApp.notifyDataSetChanged();
adapterNoApp.notifyDataSetChanged();
}
}
})
编辑:好的,所以我做了一些测试。当我使用 "Snapshot Listener" 而不是使用 .get 时,我能够节省 4 秒来检索文档快照,从 27.5 秒减少到 23.5 秒。我还发现循环本身只需要 4 秒——检索文档需要 19 秒。
然后我删除了5000个用户并用1000个用户进行了测试。 1,000 个用户的加载时间是 6.5 秒,循环本身也是。 1秒。这只是 firebase 需要解决以加快速度的问题吗?
我想出了一个大大加快搜索速度的方法。
代码没有问题。问题是它对客户端设备来说太密集了。
相反,我使用了 Cloud Functions,因此功能更强大的服务器本身会处理循环。
- 获取设备上的联系人列表。
- 将联系人列表(电子邮件或 phone 号码)发送到 firestore 数据库中的特定文档。 IE..
fsDB.doc("users/UID/device_contacts);
- 创建一个在创建该文档时激活的云功能...
exports.NewContactList = admin.firestore().doc('users/${UID}/device_contacts);
- 该函数读取文档,并查找任何 "users" 他们的电子邮件或 phone 号码 == phone 或文档中的电子邮件。
- 然后将这些用户放入一个新文档中 -
users/UID/suggestedFriends
- 然后客户端设备从创建的文档中读取建议的好友列表。
此过程仍然需要时间,但仅限于您第一次创建建议列表时。它也会在后台发生,因此设备不会停滞。然后我还创建了一个函数,当新用户添加到数据库或用户的 phone 中有新联系人时更新列表。
编辑
我写的函数...
exports.createdFriendListTest = functions.firestore.document('users/{userID}/device_contacts/device_contacts').onCreate(event => {
console.log('test worked... function called after creating doc 1st time.');
const userID = event.params.userID;
const docWithContacts = event.data.data();
console.log(docWithContacts);
var promises = []; // to hold promises within the keyList.forEach loop.
const keyList = Object.keys(docWithContacts);
keyList.forEach(key => {
var promise = admin.firestore().collection('users').where('email', '==', key).get().then(querySnapshot =>{
console.log('querySnapshot obtained');
if (querySnapshot.empty) {
console.log('there is no user ', key, ' within database.');
return true;
} else {
console.log('user, ', key, ' exists in database');
querySnapshot.docs.forEach(docSnap => {
const userExistID = docSnap.id;
console.log('that user ID is ', userExistID);
const userData = docSnap.data();
console.log('user Data', userData);
const SuggestFriend = admin.firestore().doc(`users/${userID}/suggested_friends/${userExistID}`).set(userData);
return SuggestFriend.then(result => {
console.log('suggested friend added');
return true;
})
})
}
})
promises.push(promise);
})
return Promise.all(promises);
});
我正在将用户 phone 中的联系人电子邮件列表与我的 Firestore 数据库中的用户电子邮件列表进行比较,然后创建新的 "contactsInApp" 列表。
首先,我从 firestore 数据库中获取了整个用户集合。然后为每个用户创建一个 forEach 循环,检查我的 phone 联系人列表中的每个联系人是否匹配。如果有匹配项,它会创建一个 "androidContactsInApp" 的新列表。当有少量用户时它工作正常,但当我对 5,000 名用户进行测试时,它需要更长的时间 - 大约 30 秒。我认为 firestore 应该可以很好地扩展,所以想知道我的代码是否有问题。
这是我的代码:
fsDB.collection("users")
.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
for (DocumentSnapshot document : documentSnapshots) {
String userEmail = document.get("email").toString();
for (UserInfoForRequest android_contact: arrayListAndroidContacts) {
String isEmailInDatabase = android_contact.getUserEmail();
String trimmedEmail = isEmailInDatabase.trim();
if (userEmail.equals(trimmedEmail)) {
String userID = document.getId();
UserInfoForRequest android_contact2 = new UserInfoForRequest();
android_contact2.setUserName(document.get("username").toString());
android_contact2.setUserEmail(userEmail);
android_contact2.setCurrentUID(currentUID);
android_contact2.setContactsUID(userID);
arrayListAndroidContactsInApp.add(android_contact2);
}
}
}
adapterWithApp.notifyDataSetChanged();
adapterNoApp.notifyDataSetChanged();
}
});
我也试过反转循环。这样做,我得到了我的 phone 联系人列表中的每个联系人,并为每个 phone 联系人执行查询。这意味着我没有下载整个用户集合。这种方法要慢得多——慢得多。我认为那是因为我执行单独的、单独的查询。这是我的代码:
for (final UserInfoForRequest android_contact: arrayListAndroidContacts) {
String contactsEmail = android_contact.getUserEmail();
String trimmedEmail = contactsEmail.trim();
fsDB.collection("users").whereEqualTo("email", trimmedEmail).get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
if (documentSnapshots.isEmpty()) {
Log.d("FOUNDEMAIL", " document is empty ");
}
else {
List list = documentSnapshots.getDocuments();
DocumentSnapshot doc = (DocumentSnapshot) list.get(0);
UserInfoForRequest android_contact2 = new UserInfoForRequest();
android_contact2.setUserName(doc.get("username").toString());
android_contact2.setUserEmail(doc.get("email").toString());
android_contact2.setCurrentUID(currentUID);
android_contact2.setContactsUID(doc.getId());
arrayListAndroidContactsInApp.add(android_contact2);
adapterWithApp.notifyDataSetChanged();
adapterNoApp.notifyDataSetChanged();
}
}
})
编辑:好的,所以我做了一些测试。当我使用 "Snapshot Listener" 而不是使用 .get 时,我能够节省 4 秒来检索文档快照,从 27.5 秒减少到 23.5 秒。我还发现循环本身只需要 4 秒——检索文档需要 19 秒。
然后我删除了5000个用户并用1000个用户进行了测试。 1,000 个用户的加载时间是 6.5 秒,循环本身也是。 1秒。这只是 firebase 需要解决以加快速度的问题吗?
我想出了一个大大加快搜索速度的方法。
代码没有问题。问题是它对客户端设备来说太密集了。
相反,我使用了 Cloud Functions,因此功能更强大的服务器本身会处理循环。
- 获取设备上的联系人列表。
- 将联系人列表(电子邮件或 phone 号码)发送到 firestore 数据库中的特定文档。 IE..
fsDB.doc("users/UID/device_contacts);
- 创建一个在创建该文档时激活的云功能...
exports.NewContactList = admin.firestore().doc('users/${UID}/device_contacts);
- 该函数读取文档,并查找任何 "users" 他们的电子邮件或 phone 号码 == phone 或文档中的电子邮件。
- 然后将这些用户放入一个新文档中 -
users/UID/suggestedFriends
- 然后客户端设备从创建的文档中读取建议的好友列表。
此过程仍然需要时间,但仅限于您第一次创建建议列表时。它也会在后台发生,因此设备不会停滞。然后我还创建了一个函数,当新用户添加到数据库或用户的 phone 中有新联系人时更新列表。
编辑
我写的函数...
exports.createdFriendListTest = functions.firestore.document('users/{userID}/device_contacts/device_contacts').onCreate(event => {
console.log('test worked... function called after creating doc 1st time.');
const userID = event.params.userID;
const docWithContacts = event.data.data();
console.log(docWithContacts);
var promises = []; // to hold promises within the keyList.forEach loop.
const keyList = Object.keys(docWithContacts);
keyList.forEach(key => {
var promise = admin.firestore().collection('users').where('email', '==', key).get().then(querySnapshot =>{
console.log('querySnapshot obtained');
if (querySnapshot.empty) {
console.log('there is no user ', key, ' within database.');
return true;
} else {
console.log('user, ', key, ' exists in database');
querySnapshot.docs.forEach(docSnap => {
const userExistID = docSnap.id;
console.log('that user ID is ', userExistID);
const userData = docSnap.data();
console.log('user Data', userData);
const SuggestFriend = admin.firestore().doc(`users/${userID}/suggested_friends/${userExistID}`).set(userData);
return SuggestFriend.then(result => {
console.log('suggested friend added');
return true;
})
})
}
})
promises.push(promise);
})
return Promise.all(promises);
});