1

I have a document in a collection which has an array of objects as a property.

e.g.

Projects
   name: 'Great Project'
   members: [{id:'1', name:'rob']

I want to get all projects with rob as a member.

I was hoping this would work

collection("projects")
    .where("members.name", "array-contains", "rob")
   

...but nope.

As you can see, I'm trying to get the ID

I suppose I could use a sub collection, but then I'd have a similar issue.

What am I doing wrong!

And, is this the best way to store this data?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Rob
  • 1,297
  • 2
  • 16
  • 30

1 Answers1

1

Your query currently looks for documents where the field owners is a map with a nested array of string names having rob in it. But in your sample document the field with array of objects is members. To use array-contains with an array of objects, you need to pass in the complete object as is:

const owner = {id: '1', name: 'rob'}

const db = firebase.firestore()
const projectsCol = db.collection("projects")

const query = projectsCol.where("members", "array-contains", owner)

That being said, you need to know the id field present in the object as well.

You could move members to a sub-collection instead of an array and use Collection Group queries. The database structure would look something like:

projects -> {projectId} -> members -> {memberId}

Each document in members subcollection would be similar to:

{
  id: "1",
  name: "rob",
  ...otherFields
}

Now you can run a collection group query on "members" which will return all documents where the name is "rob" and then you can use DocumentReference to all matches documents to get the project ID.

const query = firebase.firestore().collectionGroup("members").where("name", "==", "rob")

query.get().then((snapshot) => {
  console.log(snapshot.docs.map(d => d.ref.parent.parent.id))
})

This should log IDs of projects where the rob is a member.

Dharmaraj
  • 47,845
  • 8
  • 52
  • 84
  • 1
    Thank you for seeing past the question typo. You were right - I needed to pass in an entire object to the array-contains clause. I had to add .get() on the end of there query to get the snapshot but otherwise all sorted, thank you. – Rob Aug 14 '21 at 11:21
  • @RobEllis yes the `get()` method is required to fetch the document. I just did it in next line for better readability. `query.get()` – Dharmaraj Aug 14 '21 at 11:23
  • 1
    If anyone wants to get the documents after retrieving the IDs as Dharmaraj shows, you can use : await db.collection("projects").where(Firestore.FieldPath.documentId(), "in", projectids).get(); – Rob Aug 14 '21 at 13:53