I have posts collection and I want to take all the posts that its "start" field is greater that current time and user_id not equal to "1".
Query query = firebaseFirestore
.collection("posts")
.whereNotEqualTo("user_id", "1")
.whereGreaterThan("start", Timestamp.now());
I added index like on a screenshot, but still I get an error that I can’t use double condition.
What is wrong?index screenshot
An index won't help you here. The problem is that Firestore doesn't support the query you're trying to perform. Please review the documentation on query limitations to better understand:
In a compound query, range (<, <=, >, >=) and not equals (!=, not-in) comparisons must all filter on the same field.
Your query is using a range filter and an inequality filter on different fields, which is not supported.
Related
I'm trying to make social media app using flutter. one key feature with apps like this is looking for friends, and I would like to implement this in my app.
Here's a look in my Firestore Database:
We have a collection of "users" where we store their data and a subcollection "friends" where we store the userID of the added users:
Let's say user "4uuBry" is friends with user "5083CM", then "5083CM" should not be seen in a list of friend suggestion for "4uuBry".
So how do I query all users who are not friends with "4uuBry" and display them in a ListView?
EDIT Sep 18 2020
The Firebase release notes suggest there are now not-in and != queries. (Proper documentation is now available.)
not-in finds documents where a specified field’s value is not in a specified array.
!= finds documents where a specified field's value does not equal the specified value.
Neither query operator will match documents where the specified field is not present. Be sure the see the documentation for the syntax for your language.
ORIGINAL ANSWER
Firestore doesn't provide inequality checks. According to the documentation:
The where() method takes three parameters: a field to filter on, a comparison operation, and a value. The comparison can be <, <=, ==, >, or >=.
Inequality operations don't scale like other operations that use an index. Firestore indexes are good for range queries. With this type of index, for an inequality query, the backend would still have to scan every document in the collection in order to come up with results, and that's extremely bad for performance when the number of documents grows large.
If you need to filter your results to remove particular items, you can still do that locally.
You also have the option of using multiple queries to exclude a distinct value. Something like this, if you want everything except 12. Query for value < 12, then query for value > 12, then merge the results in the client.
Example:
QuerySnapshot querySnap = await FirebaseFirestore.instance
.collection('chat')
.where('participant', arrayContains: myEmployeId)
.where('type', isEqualTo: '1') //you will change the query here
.get();
I'm trying to use the not-equal (!=) operator in a query that already has a range filter (geohash query), thinking this should behave the same as an equal (==) query.
But upon running that query, I get prompted with this error message:
Unhandled Exception: The initial orderBy() field "[[FieldPath([location, geohash]), false]][0][0]" has to be the same as the where() field parameter "FieldPath([expire_at])" when an inequality operator is invoked.
Now, I understand that, due to how indexes works, firestore only allow ONE range filter per query. What I don't understand is why the not-equal operation here is considered a range filter.
In other words: Is the not-equal operation just synthetic sugar for .where(x > y).where(x < y) ?
orderBy is used to help filter and process the index's so you get the most relevant to your needs. So the error is that the fields for the orderBy must be related to the where inequality field.
You must use an orderBy on the inequality field first, just make sure the correct compound queries are generated.
I have my Firestore data with below format;
Collection: 'DataList'
Document : Autogenerated
Collection:
UserId : 3793
PassMarks: 40
Duration: 60
ObtainedMarks: 45
UserId : 3794
PassMarks: 40
Duration: 60
ObtainedMarks: 35
UserId : 3795
PassMarks: 40
Duration: 60
ObtainedMarks: 70
(similar multiple items in a list)
Working query = FirebaseFirestore.instance.collection('DataList').where('UserId', is NotEqualTo: 3793).snapshots();
I want to sort/filter list with below options;
FirebaseFirestore.instance.collection('DataList')
.where('UserId', is NotEqualTo: 3793)
.where('ObtainedMarks', isGreatedThanOrEqualTo: 'PassMarks)
.orderBy('ObtainedMarks', decending: true)
.snapshots();
(This query will generate error, and written only for better understanding of what i was looking for.)
I know complex queries could be done referring same field only and if there is '=' or '!=' is used than we couldn't merge with other queries.
Can anyone kindly advise me alternative way to obtain above result in Flutter.
As I using above $result in a ListView Builder, so I would need in above (.snapshot()) but not in (.map()) for the simplicity to use.
I assume the problem you're running into is that you're trying to do a not equal on UserId and a >= on ObtainedMarks. That is not possible, as the documentation explains:
In a compound query, range (<, <=, >, >=) and not equals (!=, not-in) comparisons must all filter on the same field.
Your options are:
Remove the filter in UserId from the query, and skip the user's document from the results in your application code. You will be reading too many documents here, but given that you're skipping only one user it may not be a lot of extra documents.
Add a field hasPassingMarks where you capture whether the user's marks are passing, and then perform an equality check (==) on that. Unlikely range operations, you can have equality checks on different fields.
I have applied index on embedded document field which is of type date. Due to unpredictable behavior of MongoDB query with $lt & $gt operators I am trying to use min() max() functions of Cursor which force both lower & upper bounds on the index. But when I used it, it gave me error:
planner returned error: unable to find relevant index for max/min query"
Query looks like:
db.user.find().min({'record.date':ISODate("2014-12-01")}).max({'record.date':ISODate("2014-12-01")}).explain()
I have indexed the field 'record.date'. I even tried to force it with hint() but of no use. It showed me this error:
planner returned error: hint provided does not work with min query"
Somewhere on the Internet I saw on one of the forums that we can query with embedded fields in min(), max() functions. Field 'record' is an array of sub-documents. I have another field of type date in main document for which min(), max() worked fine (this field is indexed too). Can anyone guess why is this happening?
sample document:
user:
{name:'ad',dob: ISODate('yyyy-mm-dd'),createdAt: ISODate(),...,record:[
{date:ISODate:(),...
},...]}
Index was created as:
db.user.ensureIndex({'record.date':1})
Thanks.
If there is a MongoDB collection that contains documents with field foo with both integer timestamps and ISODate objects, what will the resulting order of a sorted query be?
Will one of the objects come before the other, or will they be compared and interleaved?
The reason I ask is because this is true in Javascript (see below), but I'm wondering what will happen in MongoDB's underlying implementation.
> new Date(400) <= 401
true
> new Date(401) <= 400
false
MongoDB does type checking and conversion for certain comparison and not for all of them. I would suggest looking further in the documentation at http://docs.mongodb.org/manual/reference/method/cursor.sort/#behaviors to see how the sort behaves in ordering when the types are different.