This question already has answers here:
Firestore search array contains for multiple values
(6 answers)
Closed 3 years ago.
I am looking at Firebase, cloud firestore and I am not understanding how I would perform a query and pass in an array.
const friendIds = [1, 2, 3];
Firestone.collection('conversations')
.where('members', 'array-contains', friendIds)
.get()
.then(querySnapshot => console.log(querySnapshot))
.catch(error => console.log(error));
anyone know how to achieve this?
This is currently not possible with a single query. array-contains can only find a single item in the named array.
Your alternative is to perform three queries, one for each item in the friendsId array, then merge the results in your code.
Not sure if this is possible, but here's an example from the Firebase Node.js Snippets that can give you an idea:
let citiesRef = db.collection('cities');
// [START array_contains_filter]
let westCoastCities = citiesRef.where('regions', 'array-contains',
'west_coast');
// [END array_contains_filter]
westCoastCities.get()
.then(res => {
console.log('West Coast get: ', res);
});
Reference Documentation
According to the official documentation regarding query operators:
You can use the array-contains operator to filter based on array values.
As I can see in your code, your friendIds argument that is passed as the third parameter to the where() function is of type array. What you are actually doing, you are searching in the members property which is of type array for an array, which is actually not possible since I assume the members array in your database contains numbers.
An query like this:
Firestone.collection('conversations')
.where('members', 'array-contains', 3)
.get()
.then(querySnapshot => console.log(querySnapshot))
.catch(error => console.log(error));
Will work perfectly fine because we are searching within the members array for a number.
If you need to query for all those numbers, you should perform three separate queries and combine the result client side.
Related
I don't think I'm very far from the answer, I tried to query an id inside an array on Firestore.
I wanna compare the id of the participants.
Also my DB in Firestore:
And also my function, for the moment my function return size =0 so they can't catch the query.
const deleteAbuse = (type) => {
const participants = channel?.otherParticipants;
if (!participants || participants.length != 1) {
return;
}
const myID = currentUser.id;
const otherUserID = participants[0].id;
console.log('id user', otherUserID);
channelDB
.where('participants.id', '==', otherUserID)
.get()
.then((querySnapshot) => {
console.log(querySnapshot.size);
querySnapshot.forEach((doc) => {
console.log(doc.ref);
//doc.ref.delete();
});
});
};
There is no way you can query filter your "channels" collection to get documents based only on a single field of an object that exists inside the participants array. In other words, you cannot create that filtering based only on that ID. To be able to filter the data, you should pass to the where() function, the entire object, and not only some partial data. The object should contain values for all the fields. Only the ID is not enough.
And also my function, for the moment my function return size =0
That's the expected behavior since in your array there isn't any object that holds only a single field called id. All objects hold 7 fields, or even more than that, as I cannot see all fields in your screenshot.
I wrote an article called:
How to update an array of objects in Firestore?
Where you can find in the first part, the simplest way to get a custom object from an array of custom objects.
Alternatively, you can create an array that can hold only the IDs of the participants, filter the documents and create another database call to get their corresponding data.
I have a firebase collection called activity with 4 documents inside, with timestamps of 2, 3, 4, and 5 o'clock.
When I query it like so
let postsQuery = firebase
.firestore()
.collection(`activity`)
.orderBy("timestamp", "desc")
.limit(2);
I correctly get the 5 and 4 o'clock posts.
However, when I call the function again with the following conditional:
// oldest post is the 4 o'clock document
if (oldestPost) {
postsQuery = postsQuery.startAfter(oldestPost);
}
I get the 4 and 5 documents again. If I change startAFter to be any other filter, I get 0 documents returned.
So my question is, am I just doing it wrong, OR can I not pass in a document.data() as the filter, and i need to pass in the original document instead?
So answering my own questions:
when i got my posts, I was just storing them in an idMap
postsQuery
.get()
.then((documents) => {
const typeIdToDocument = {};
documents.forEach((document) => {
const data = document.data();
typeIdToDocument[document.id] = { id: document.id, ...data };
});
Then when I passed in an startAfter, I used the .data() result of the post.
However, it worked when-
A) I passed in the original firebase document, not the .data() version
OR B) I passed in the Firebase Timestamp, rather than the full document
postsQuery = postsQuery.startAfter(oldestFirebaseTimestamp);
There are two overloads of startAfter:
startAfter ( snapshot : DocumentSnapshot < any > ), which is the one I recommend you use whenever you can
startAfter ( ... fieldValues : any [] ), into which you can pass just the field values of the document to start after.
The reason I recommend the first overload is that there may be cases where you have multiple documents with the same field value. The first overload is smart enough in that case to use the document ID to disambiguate between those and not return any overlapping documents. The second overload can't guarantee that.
This question already has an answer here:
Firestore array-contains-any is not working properly
(1 answer)
Closed 3 years ago.
Hello i'm implementing the array-contain query but everytime i'm trying i'm Getting blank snapshot. My code is:
getStation = () => {
const query = firebase
.firestore()
.collection('routes')
.where('station', 'array-contains', 'station_name ');
query.get().then(snapshot => {
console.log("snapshot", snapshot);
snapshot.docs.forEach(doc => {
alert("eri")
console.log("eryh", doc.data);
})
})
.catch(err => {
console.log('Error getting documents', err);
});
}
I even tried to pass the static values but not able to get the desire value.
In your code there is a problem with typo mistake station must be stations
.where('station', 'array-contains', 'station_name ');
must be
.where('stations', 'array-contains', 'station_name ');
I hope it will fix your problem.
Update Answer
There is also typo mistake in station_name you just added the space after station_name
.where('station', 'array-contains', 'station_name ');
must be
.where('stations', 'array-contains', 'station_name');
You are trying to use array-contains to check for a field inside a map. This is not supported.
The array-contains can only search for a field inside the array and not a field inside a map which is inside that array.
A workaround I have tested is that you add an extra field inside the array that will be a boolean or a string and you can query based on it.
Using a boolean field in the array:
.where('stations', 'array-contains', true);
Using a String field in the array:
.where('stations', 'array-contains', 'station_name exists');
The array-contains operation checks if the precise object/value you specify exists in the array. It can't check on subsets of the array elements, only on complete values. So in your current structure, you'd have to pass all properties into the array-contains call:
.where('station', 'array-contains',
{ station_address_name: '...', station_lat_long: ..., status_name: '...' });
This typically is not feasible, in which case you'll want to store the elements that you want to filter on in a (additional) separate field in your documents. In this example, since you want to filter on station names, you'd add a field station_names where you store just the station names. Then you can query with:
.where('station_names', 'array-contains', 'name to search for')
Also see:
Firestore to query by an array's field value
Firestore array-contains-any is not working properly
How to make query spot only the some value in a Map inside an Array in flutter (dart)?
I have a query that is not working as I expect it to. I have a collection called 'games' that has a number of documents in it.
Each document has an array called 'hiScores' that consists of the results from that round. I would like to query all games for a specific player for example:
.where('hiScores.playerName', '==', 'David Lamm')
This is not returning anything. I have no problems when querying a top level variable in the document. What have I done wrong?
Database:
db.collection('games')
.where('hiScores.playerName', '==', 'David Lamm')
.get()
.then(function(querySnapshot) {
console.log('Davids games:')
querySnapshot.forEach(function(doc) {
console.log(doc.id, " => ", doc.data());
});
})
.catch(function(error) {
console.log("Error getting documents: ", error);
}
);
The problem is that the hiScores field is an array, not an object. You can tell it's an array because the first immediate element of the array in the screenshot has index 0. You're trying to query hiScores as if it's a single object with a single property called playerName.
Firestore doesn't support querying for object properties within within array fields. If you have an array field, you can only query to find documents where an entire item is present in the array (an arrayContains query).
As pointed out by Doug this is currently not possible in firestore.
You can create a top level array of strings in each game named playerNames[]. Then use the where condition on playerNames with array_contains.
I am working a lot with firebase, and am trying to load certain information from the database. The original data comes from a query, and is returned to me in a POJO. The console prints this when the original data is returned:
-KhQ76OEK_848CkIFhAq: "-JhQ76OEK_848CkIFhAq"
-OhQ76OEK_848CkIFhAq: "-LhQ76OEK_848CkIFhAq"
What I need to do is grab each of the values (-JhQ76OEK_848CkIFhAq and -LhQ76OEK_848CkIFhAq) separately, and query the real-time database again for each one. I can manage that aspect, but I cannot seem to figure out how to separate the values.
I have already tried to get a single output by doing:
console.log(vals[0]) but it just returned undefined, and splitting the string by " would be very inefficient for large data sets. Any ideas?
To access the values, you can iterate the snapshot's children using the snapshot's forEach method. The keys and values of the children can be obtained using the key property and the val() method:
firebase.database()
.ref("some/path")
.once("value")
.then((snapshot) => {
snapshot.forEach((childSnapshot) => {
console.log(childSnapshot.key); // The child's key: e.g. "-KhQ76OEK_848CkIFhAq"
console.log(childSnapshot.val()); // The child's value: e.g. "-JhQ76OEK_848CkIFhAq"
});
});
To solve this issue, all I did was convert the object returned into an array by using this code below:
var Array = Object.keys(datalist).map(function(k) { return datalist[k] });
Works like a charm, and I can now run a simple for loop for Array