0

I have the below data structure for the members property in my teams collection.

enter image description here

and I am trying to write the below query via triggers to update the structure whenever there is an update on the members collection.

const teamData = await firebaseAdmin
        .firestore()
        .collection('teams')
        .where('members', 'array-contains', { id: change.after.id })
        .get();

But this always returns an empty set of collections even though the data matches. I referred this post and then tried as below wherein I had compared complete object with the data available in the before context. But again even that would return the empty result set.

const memberBefore = change.before.data() as Member;
const teamData = await firebaseAdmin
        .firestore()
        .collection('teams')
        .where('members', 'array-contains', [
          {
            id: change.after.id,
            name: memberBefore.name,
            nameKa: memberBefore.nameKa,
            img: memberBefore.img,
          },
        ])
        .get();

Could someone help me out to resolve this issue?

Guruprasad J Rao
  • 29,410
  • 14
  • 101
  • 200

1 Answers1

2

arrayContains does NOT match subfields - it matches the entire entry. And to be totally honest, Firestore "arrays" are ABSOLUTELY NOT ARRAYS - they are "ordered lists" - the "number" is their order, not an index. I suspect, also, that the ORDER of the entries in the object are important, as well, so your screenshot order:

{
id: "xxxxxx",
img: "xxxxx",
name: "xxxxx",
nameKa: "xxxxx"
}

WILL NOT MATCH

{
id: change.after.id,
name: memberBefore.name,
nameKa: memberBefore.nameKa,
img: memberBefore.img,
}

Firestore's scale and speed come from indexing entries, and an "array" (ordered list) of objects is essentially indexed by a string-like representation of the object.

Firestore "arrays" (ordered lists) of objects are remarkably difficult to use, and give you no advantages - they are much better suited to "single value" entries. I would strongly recommend using a sub-collection of documents (each member in it's own document), where you can trivially query (either a a collection or collectionGroup) to find individual documents.

LeadDreamer
  • 3,303
  • 2
  • 15
  • 18
  • It still doesn't work with the properly ordered query as well LeadDreamer. But yea, if I go with sub-collection, it would still be counted separately for the read stats when I fetch the collection and sub-collection right? I think I would better go with storing the individual ids in an array and update the objects once the document is fetched. – Guruprasad J Rao Jun 14 '21 at 04:27
  • 1
    I would recommend *against* over-optimizing reads early in your process - most often, your data structures will change during development, and you can more easily optimize later. If you insist on such early optimization, the SIZE of a document is relatively free, so "denormalizing" into multiple ordered lists, maintained in client/server code, can help, where each ordered list has *one* part of your structure and they are maintained in the same order. A good example is a Map of Arrays - Users.Id[], Users.name[], Users.nameKa[] etc - you can use the dotted notation for your arrayContains. – LeadDreamer Jun 14 '21 at 17:28