最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Firebase Firestore query an array of more than 10 elements - Stack Overflow

programmeradmin10浏览0评论

[

I am trying to query the post-collection with the user settings but the settings is an array of more than 10 elements and nothing is returned. I know the documents did mention the limit of 10 elements, does anyone know a workaround?

firebaseApp.collection('posts')
            .where("newTag", "in", mySettings)
            .get()
let array = [];
        posts.forEach((post) => {
            array.push(post.data());
        });

dispatch({ type: ActionTypes.GET_POSTS, payload: array });

[

I am trying to query the post-collection with the user settings but the settings is an array of more than 10 elements and nothing is returned. I know the documents did mention the limit of 10 elements, does anyone know a workaround?

firebaseApp.collection('posts')
            .where("newTag", "in", mySettings)
            .get()
let array = [];
        posts.forEach((post) => {
            array.push(post.data());
        });

dispatch({ type: ActionTypes.GET_POSTS, payload: array });
Share Improve this question edited Dec 10, 2019 at 21:34 marc_s 755k184 gold badges1.4k silver badges1.5k bronze badges asked Dec 9, 2019 at 22:45 Cho ChoCho Cho 1571 gold badge3 silver badges13 bronze badges 0
Add a comment  | 

5 Answers 5

Reset to default 4

A simple function to chunk the array could solve your problem:

const chunkArray = (list: any[], chunk: number): any[][] => {
    const result = [];

    for (let i = 0; i < list.length; i += chunk) {
        result.push(list.slice(i, i + chunk));
    }

    return result;
};

export { chunkArray };

Then a for await hack to get the snaps would work as well:

  const snaps_collection: FirebaseFirestore.QuerySnapshot[] = [];

  for await (const snap of chunks.map(
    async (chunk) =>
      await database
        .collection("collection_name")
        .where("id", "in", chunk)
        .get()
  )) {
    snaps_collection.push(snap);
  }

The workaround is to perform a query for each item in mySettings individually, and merge the results on the client. Or, split mySettings into another collection of arrays that each have 10 or less items, query for each one of those individually, and merge the results on the client.

Do a wherein using a chunk of the array of mysettings, each chunk could have a maximum size of 10, then join the results into a single array

This solution using typescript, you can convert this one into your programming language.

Time Complexity: while loop running length / 10 times.

export async function getUsersByIds(ids: [string]) {
    let users = []
    const limit = 10

    while (ids.length) {
        const res = await db
            .collection('users')
            .where('uid', 'in', ids.slice(0, limit))
            .get()
        const _users = res.docs.map((doc) => {
            const _data = doc.data() as UserModel
            _data.docId = doc.id
            return _data
        })

        users.push(..._users)
        ids.splice(0, limit)
    }

    return users
}

Here is more Typescript eslint friendly way(no usage of any)

Array chunk method in ArrayUtils.ts

export function chunk<M>(array: Array<M>, chunkSize: number) {
  const ans: Array<Array<M>> = [];
  for (let i = 0; i < array.length; i += chunkSize) {
    ans[Math.floor(i / chunkSize)] = array.slice(i, i + chunkSize);
  }
  return ans;
}

now in FirebaseUtils.kt, you can write

import { chunk } from "./ArrayUtils";

export async function inQuery<M>(
  docRef: FirebaseFirestore.CollectionReference,
  field: string | FirebaseFirestore.FieldPath,
  values: Array<string>
) {
  const querySnapshots = await Promise.all(
    chunk(values, 10).map((chunkedArray) => {
      return docRef.where(field, "in", chunkedArray).get();
    })
  );
  return querySnapshots
    .flatMap((querySnapshot) => querySnapshot.docs)
    .map((documentData) => documentData.data() as M);
}

Few advantages over this answer

  1. Refactored as proper utility methods for reusability
  2. Used Promise.all which is parallel and more recommended than for await as later is used when we don't have all the promises upfront. See this
发布评论

评论列表(0)

  1. 暂无评论