Firestore: Query by Item in Array of Document

Firestore: Query by item in array of document

Added 'array-contains' query operator for use with .where() to find documents where an array field contains a specific element.

https://firebase.google.com/support/release-notes/js 5.3.0

Update: also available in @google-cloud/firestore: https://github.com/googleapis/nodejs-firestore/releases/tag/v0.16.0

Update 2 https://firebase.googleblog.com/2018/08/better-arrays-in-cloud-firestore.html

Update 3 now available in Admin Node.js SDK v6.0.0 https://github.com/firebase/firebase-admin-node/releases

Firestore: Query by item in array

There is no operator to filter based on an item at a specific index in an array. If you need that, as you already said, you will need to put the relevant value from the array in a separate field and filter on that.

There are currently no plans to add such an operation, but you can always weigh in with a feature request.

How to Query within an array of object in Firestore?

To use array-contains on an array of objects, you must know the entire object. It seems feasible in this case if you know UID of current user and role as well. Try running the following query:

const userId = firebase.auth().currentUser.uid

db.collection('chatRooms')
.where('users', 'array-contains', { id: userId, role: 'Admin' })
.get()
.then((snapshot) => {
setRooms(
snapshot.docs.map((room) => {
return { id: room.id, data: room.data() };
})
);
});

The above query will return documents where users array contains current user's UID with 'Admin' role only! There's currently no way to query based on a single field in array of object.

If you don't know user's role then you might have to store users as a sub-collection instead of array.

How to use array-contains operator with an array of objects in Firestore?

To use array-contains with an array of objects, you need to pass the complete object you are looking for in that array.

For example,

const lessonObj = {
Title: "Leven vanuit verlossing",
Description: "the desc",
...allTheOtherFieldsAsIs
}
firebase.firestore().collection("Modules").where("Lessons", "array-contains", lessonObj)

You should ideally use a sub-collection to store lessons in a module. Then you can easily query lessons using the following query:

const db = firebase.firestore()

const lessonsSnapshot = await db.collection("Modules")
.doc("moduleID")
.collection("Lessons")
.where("Title", "==", "Leven vanuit verlossing")
.get()

console.log(lessonsSnapshot.docs[0].data())

How to query a Firestore collection with an array filter?

In operator returns documents with field that can be equal to many values, not just one. For example, .where('country', 'in', ['France', 'Germany']) will return documents where country is equal to France or Germany. In operator is meant to be used on number and string field, not arrays. What you need is .where('users', 'array-contains', user.id). If you want to search for more than one user use 'array-contains-any' it works same as 'in' operator but for arrays.

Query by item in array of document, and sort by item's position in the array

Cloud Firestore doesn't support querying arrays by ranked index. The only way you can query an array is using an array-contains type query.

What you could do instead is organize your colors using maps where the color is the key and their rank is the value:

name: "Tyrannosaurus rex",
dominantColors: {
"beige": 1,
"blue": 2,
"green": 3
}

Then you can order the query by the value of the map's property. So, in JavaScript, it would be something like this:

firebase
.collection('dinosaurs')
.where('dominantColors.green', '>', 0)
.orderBy('dominantColors.green')

Querying arrays within documents in Google Firestore

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.



Related Topics



Leave a reply



Submit