1

In my app I currently have three collections:

db_contacts

Firestore-root
    |
    --- db_contacts (collection)
         |
         --- phoneNumber (document)
              |
              --- 'phone': phoneNumber

db_contacts holds a list of mobile phone that I add before head. The collection will contain about 1 million phone number later on. Currently it only holds 50,000 phoneNumber (50,000 documents).

users_contacts

Firestore-root
    |
    --- users_contacts (collection)
         |
         --- uid (document)
              |
              --- contacts (subcollection)
                   |
                   --- phoneNumberOfContact (document)
                          |
                          --- 'phone': phoneNumberOfContact

users_contacts holds all of the phone numbers of every user on my app. The app will be used by about 10,000 users each having ~500 contacts. So I will have 10,000 uid document and each have ~500 phoneNumberOfContact document inside the contacts subcollection.

users_common_contacts

Firestore-root
    |
    --- users_common_contacts (collection)
         |
         --- uid (document)
              |
              --- contacts (subcollection)
                   |
                   --- phoneNumberOfContact (document)
                          |
                          --- 'phone': phoneNumberOfContact

users_common_contacts contains the contacts a user have that are already in the db_contacts. I'm populating this collection on an event hook set on the users_contacts onWrite.

My Use Case

I need to create an extra collection, that stores the unique contacts of a user that are inside the users_common_contacts. What contacts only this user have in common with the db_contacts and that no other user have.

What I did so far, and turned out to be a mistake is the following:

users_unique_contacts

Firestore-root
    |
    --- users_unique_contacts (collection)
         |
         --- uid (document)
              |
              --- contacts (subcollection)
                   |
                   --- phoneNumberOfContact (document)
                          |
                          --- 'phone': phoneNumberOfContact

My Problem

I couldn't correctly populate this table, as there's no way to find the unique contacts of a single user. My code for populating users_unique_contacts is as follow:

exports.userCommonContactsListener =
    functions.firestore.document('users_common_contacts/{userID}/contacts/{documentID}')
        .onCreate((snap, context) => {
            const DocumentID = context.params.documentID;
            const UserID = context.params.userID;

            const uniqueContactsRef = admin.firestore().collection('users_unique_contacts').doc(UserID).collection("contacts");

            return new Promise((resolve, reject) => {

                uniqueContactsRef.where('phone', '==', DocumentID).get().then(contactSnapshot => {
                    if (contactSnapshot.size > 0) {
                        console.log(`Found Common Number in Unique ${contactSnapshot}`);
                        contactSnapshot.forEach(documentSnapshot => {
                            documentSnapshot.ref.delete();
                            console.log(`Deleted ${documentSnapshot.ref.id} as unique contact`);
                            resolve(`Deleted ${documentSnapshot.ref.id} as unique contact`);
                        });
                    } else {
                        var db_contacts = {}
                        db_contacts['phone'] = DocumentID;
                        db_contacts['timestamp'] = new Date();
                        uniqueContactsRef.doc(DocumentID).set(db_contacts, { merge: true }).then((res) => {
                            console.log(`Added ${DocumentID} as unique contact`);
                            resolve(`Added ${DocumentID} as unique contact`);
                        }).catch((err) => {
                            console.log(err);
                            reject("Error Removing Unique Contact", err);
                        });;
                    }
                });
            });

        });

The code is not working, the uniqueContactsRef.where('phone', '==', DocumentID).get() is never returning any values.

How can I go in modeling my users_unique_contacts?

Update:

Further Explanation

What do I mean by: "I need to create an extra collection, that stores the unique contacts of a user that are inside the users_common_contacts. What contacts only this user have in common with the db_contacts and that no other user have."

Lets say db_contacts have the following numbers:

  • 111111
  • 222222
  • 333333
  • 444444
  • 555555
  • 123456

User A have in Common with db_contacts the following numbers:

  • 111111
  • 222222
  • 555555
  • 444444
  • 123456

User B have in Common with db_contacts the following numbers:

  • 111111
  • 222222
  • 333333
  • 555555

Now User A is the only one to have in common the following numbers:

  • 444444
  • 123456

Now User B is the only one to have in common the following numbers:

  • 333333

So User A's unique numbers are:

  • 444444
  • 123456

So User B's unique numbers are:

  • 333333
Lambasoft
  • 909
  • 2
  • 14
  • 33
  • *"I need to create an extra collection, that stores the unique contacts of a user that are inside the users_common_contacts. What contacts only this user have in common with the db_contacts and that no other user have."* Aren't all the contacts unique since user contacts exists in both places? What is the desired result? – Alex Mamo Feb 18 '19 at 12:54
  • @AlexMamo Hey! I have added an example hopefully to be able to explain what I meant. Thank you :) – Lambasoft Feb 18 '19 at 13:04

1 Answers1

1

Since the db_contacts collection already contains all phone numbers of all users, you don't need to compare the uniqueness of user phone numbers with what exist in db_contacts collection, you need to check if the numbers a user has, exist or not in other user contact list. With other words, you need to check if a number is unique compared with other user contacts. So you need to get each number a user has and check if it exists in other user contact list. In this case, you should change your database schema a little bit by adding a new collection like this:

Firestore-root
   |
   --- allUsersNumbers (collection)
         |
         --- uid (document)
             |
             --- phoneNumbers (map)
                   |
                   --- phoneNumberOne: true
                   |
                   --- phoneNumberTwo: true

See, uid document now holds only a map, so it can fit in the 1MiB, which is the max size of the document. This is how your query should look like:

allUsersNumbersRef.where('phoneNumbers.searchedPhoneNumber', '==', true);

Now you only need to get the data. If the snapshot exists it means that is not unique, if doesn't exist it means that is unique. You can also store those numbers in an array if you want. So it's up to you to decide which solution is better for you.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Thanks a lot for your answer. I have added the common numbers collection for performance issues. I suppose it is faster to search common numbers which holds less content than searchin all the users numbers? Another question, is it ok to add an array of about 1000 phone numbers? Thank you Alex! – Lambasoft Feb 18 '19 at 13:39
  • Oh and I think you mistaken db_contacts to users_contacts – Lambasoft Feb 18 '19 at 13:41
  • Unfortunately, Firestore doesn't support [queries across different collections](https://stackoverflow.com/questions/52696311/cloud-firestore-how-to-get-relational-data-from-two-collections) in one go. So you definitely need to store that data in a single collection so it can be queried. – Alex Mamo Feb 18 '19 at 13:42
  • So you got the idea? – Alex Mamo Feb 18 '19 at 13:53
  • Yes thank you. I was just checking how to delete 1 specific item from a map, so when a phone number of a user isn't unique anymore, how to remove that specific number from a Map. I will mark this as resolved :) – Lambasoft Feb 18 '19 at 13:57
  • Yes, that correct, just remove it from the map. You're welcome, cheers! – Alex Mamo Feb 18 '19 at 13:58