如何减少Firestore读取操作?

时间:2020-10-30 17:17:37

标签: javascript firebase google-cloud-firestore

我有一个聊天应用,我需要将用户联系人用户集合匹配。

// assume there is 100 contacts
const phoneContacts = {"91302034403": "Salman", "xxx": "xxx"};

// assume there is 30 contacts
const contactsUsingMyApp = ["91302034403", "xxx"];

// assume there is 30000 users
const snap = await db.collection('users').get();
const docs = snap.docs;

for (let i = docs.length - 1; i >= 0; i--) {
   
    const data = docs[i].data();
    const phone = data.phone;

    if (phoneContacts[phone] !== undefined){
      contactsUsingMyApp.push(phone);
    }
       
}

出了什么问题?

  1. 我的用户集合中有30000个用户。
  2. 每天 200个新用户安装我的应用
  3. 上面的代码执行。仅在注册

现在让我们计算一下

  1. 200 x 30000 = 6000000 read operations 每天
  2. $0.06/100000 reads
  3. 6000000/100000 = 60 * $0.06 * 30day = $108/m

以上内容也可伸缩,并且仅针对读取操作计算,这确实很昂贵,如何减少它,直到可以使用firebase?

为什么我要阅读整个收藏集以进行注册?因为注册中只有一个请求。

为什么我不像下面那样寻找用户联系人,因为与上面的操作相比,操作要少得多,因为有许多请求

// assume there is 100 contacts
const phoneContacts = {"91302034403": "Salman", "xxx": "xxx"};    

const phonesArray = Object.keys(phoneContacts);

for (let i = phonesArray.length - 1; i >= 0; i--) {
   
    const snap = await db.collection('users')
    .where("phone", "==", phonesArray[i]).get();

    if (snap.size > 0){
      // this contact is registered with this app
    }
       
}

不,您看到的是,有很多请求,就像我们在循环中所请求的一样。

1 个答案:

答案 0 :(得分:1)

in query可能允许您以较少的每位用户读取次数来实现此目的,但是由于in查询最多需要10个值,因此您需要按块检查联系人:

const chunk = (arr, size) => arr.length ? [arr.slice(0, size), ...chunk(arr.slice(size), size)] : [];

const contactsWithApp = Promise.all(
  chunk(Object.keys(phoneContacts)).map(
     it => db.collection("users").where("phone", "in", it).get()
  )
).flat();

或者,您可以在应用程序中缓存所有用户,并不时更新缓存:

let phones = new Set();

async function updateCache() {
 phones = new Set();
 (await db.collection("users").get()).forEach(user => phones.add(user.phone));
}

const contactsWithApp = Object.keys(phoneContacts).filter(it => phones.has(it));