Firebase/Firestore: Is it possible to query .where(x == foo || x == bar)? [duplicate] - firebase

This question already has an answer here:
How to accomplish WHERE IN query in Cloud Firestore [duplicate]
(1 answer)
Closed 3 years ago.
I have a collection of users, which looks like this:
Each follower/following document is structured like this:
{
uid: ...,
}
I want to create a query that satisfies these criteria:
Get the users that you are following
Ordered by their 'lastPosted' time (so you're getting the users who have posted most recently first)
Since the follower/following subcollections only contain references to full user documents, and not the full documents themselves, it's not as easy as just querying the following subcollection.
This is what I've tried:
database
.collection('users')
.doc(myUid)
.collection('following')
.get()
.then(followings => {
database
.collection('users')
.orderBy('lastPosted', 'desc')
.where('uid', '==', following[0] || following[1] ...)
})
Which doesn't work. I have also thought about this:
database
.collection('users')
.orderBy('lastPosted', 'desc')
.where(myUid exists in their followers subcollection)
I'm not sure where to go from here, or whether firestore even allows this.

See:
https://firebase.google.com/docs/firestore/query-data/queries#query_limitations
Logical OR queries. In this case, you should create a separate query for each OR condition and merge the query results in your app.

Related

Flutter: Better way to update many documents in a single call [duplicate]

This question already has answers here:
Can Firestore update multiple documents matching a condition, using one query?
(8 answers)
Firestore update all documents in collections
(6 answers)
How to do a bulk update in Firestore
(4 answers)
Closed 9 months ago.
I have a function that allows a user to change their username, simply using firebase update({}). Every time a user sends a message in my chat page, it saves it as a documents on firebase with related data, user name, time message was sent etc.
The function below is for a chat page, which works how I want it to. it takes whatever the current users username and updates all past messages with the users new current username. I want to know if their is a better way to achieve this.
How can I change a single value in any amount of documents, which obviously have different ids, in one single call?
List<String> testList = []; //<--- List of document IDs of previous messages user has sent
FirebaseFirestore.instance
.collection('users')
.doc(loggedInUser.uid)
.update({'messageID': testList});
for (var item in testList) {
var collection = FirebaseFirestore.instance
.collection("chatrooms")
.doc(chatroom)
.collection("users")
.doc('ggg')
.collection("userMessage");
collection
.doc(item) // <-- Doc ID where data should be updated.
.update({'username': loggedInUser.userName.toString()}) // <-- Updated data
.then((_) => print('Updated'))
.catchError((error) => print('Update failed: $error'));

how to get collection list from document Id in flutter Firestore? [duplicate]

This question already has answers here:
Flutter & Firebase: Return list of collections
(2 answers)
Fetching all collections in Firestore
(3 answers)
How to list subcollection on firestore? [duplicate]
(1 answer)
Closed 1 year ago.
i want "a9XvvHPEvhfDWTXe8HqPqWuP2gg1" this documentId collection list.
FirebaseFirestore.instance
.collection('tbl_FriendList').doc(
'a9XvvHPEvhfDWTXe8HqPqWuP2gg1').get().then((event) {});
You can't do that with the Flutter sdk. You'll need to restructure your data.
Retrieving a list of collections is not possible with the mobile/web
client libraries. You should only look up collection names as part of
administrative tasks in trusted server environments. If you find that
you need this capability in the mobile/web client libraries, consider
restructuring your data so that subcollection names are predictable.
https://firebase.google.com/docs/firestore/query-data/get-data#list_subcollections_of_a_document
As per you image, seems like there is no document in this ID. You only have sub-collections.
To get sub-collection you have to improve your query and you should know your sub-collection name as mentioned below
await FirebaseFirestore.instance
.collection('tbl_FriendList')
.doc('a9XvvHPEvhfDWTXe8HqPqWuP2gg1')
.collection('collectionPath')
.get();
Or you have to store data in db like this
a9XvvHPEvhfDWTXe8HqPqWuP2gg1 > collectionName > documents
FirebaseFirestore.instance
.collection('tbl_FriendList')
.doc('a9XvvHPEvhfDWTXe8HqPqWuP2gg1')
.collection('collectionName')
.add({'data': 'data123'});
after that you can get data as mentioned below
FirebaseFirestore.instance
.collection('tbl_FriendList')
.doc('a9XvvHPEvhfDWTXe8HqPqWuP2gg1')
.collection('collectionName')
.get()
.then((value) => {});
This query will return all data you have in collectionName sub-collection.

Firestore collection group query on document id [duplicate]

This question already has an answer here:
How to perform collection group query using document ID in Cloud Firestore
(1 answer)
Closed 1 year ago.
I am trying to run the following query:
this.db.firestore
.collectionGroup('members')
.orderBy('dateModified', 'desc')
.where(firebase.firestore.FieldPath.documentId(), '==', uid)
But I get the error:
Invalid query. When querying a collection group by
FieldPath.documentId(), the value provided must result in a valid
document path, but 'X6yL5Ko55jSMWhhoQUO91xVYdEH3' is not because it
has an odd number of segments (1).
Is the only way around this to add the document id to the document?
This is not ideal as I have a lot of existing data...
The document id is the uid of the firebase user.
As the error message says, for an index on a collection group the documentId() field values are actually stored as document paths to ensure unique lookups of those values in the index.
If you want to also query on document ID over a collection group, you will indeed have to store the ID as a field value in each document.
Also keep in mind that it is then possible to get multiple documents for the query, even though that is astronomically unlikely if you use the built-in add() operation.
Adding the uid to the document itself is the only possible way at the moment and then query on that field:
this.db.firestore
.collectionGroup('members')
.orderBy('dateModified', 'desc')
.where("uid", '==', uid)
There was a Github issue for the same and explains why that's not possible.
That's pretty much why I sometimes prefer to store a root level collection members. Each document in the collection will have contain the groupID (or whatever your parent collection is meant for). If you use userID as the key for documents in there then it goes easy.
this.db.firestore.collection("members").doc(uid)
So instead of having a path like: /groups/{groupID}/members/{memberID}, the structure will be like: /groups/{groupID} and all the members will be store in the root level collection 'members'. A document in that collection may look like:
// uid as doc key
{
groupId: "groupID",
...otherFields
}
The catch is if a member can join multiple groups you cannot use the userId as the key.

Flutter Firebase: Retrieve a list of documents, limited to IDs in an array?

I'm working on a Flutter app where each user can create projects, and share projects with other users. I've created a 'shares' collection, where each user's ID is a document, and within that document, all project IDs that have been shared with that user are collected like so, with a boolean that represents whether or not the share has been accepted yet:
Next, I created a collection of the projects themselves, like so:
Now, I'd like to query the 'projects' collection and return only the projects that are in a given user's 'shares' list. First off, how can I get each document in the share list's ID? And secondly, is it possible to compare that ID to the contents of a List using a .where() clause?
I've been trying something like this, but to no avail:
Stream<List<Map<String, dynamic>>> getListOfProjectsForUser({#required List<String> shares}) {
var ref = _firestore.collection('projects');
return ref
.where(shares, arrayContains: ref.id)
.snapshots()
.map((QuerySnapshot snapshot) => snapshot.docs.map((DocumentSnapshot doc) => doc.data()).toList());
}
I also tried this:
Stream<List<Map<String, dynamic>>> getListOfProjectsForUser({#required List<String> shares}) {
var ref = _firestore.collection('projects');
return ref
.where(shares, arrayContains: FieldPath.documentId)
.snapshots()
.map((QuerySnapshot snapshot) => snapshot.docs.map((DocumentSnapshot doc) => doc.data()).toList());
}
Is what I'm trying to do even possible? I've been messing with this for two days and my head's exploding. Any help would be greatly appreciated. Thanks in advance.
You'll need two operations.
Read the document for the user, to determine the list of project IDs.
Perform a in query for the project documents matching those IDs. The in operator accepts up to 10 IDs, so if you have more than 10 projects you'll need multiple queries and merge the results in your application code.
var citiesRef = db.collection("projects");
citiesRef.where(FieldPath.documentId, arrayContains: ['project1id', 'project2id']);
Also see:
The FlutterFire documentation for the where(field, whereIn:) operation
The FlutterFire documentation for the FieldPath.documentId field
First off, how can I get each document in the share list's ID?
For this, you're required to actually query the entire collection. You can iterate the results to collect the IDs of each document. There is no easy way to just get a list of IDs directly from web and mobile client code. See: How to get a list of document IDs in a collection Cloud Firestore?
And secondly, is it possible to compare that ID to the contents of a List using a .where() clause?
If you have a list of document ID strings in memory that could be any length, you will need to perform a query filtering projects for "projOwner" for each individual ID. There are no SQL-like joins in Firestore, so you can't simply join the two collections together with a single query.
Here's how you do a single one - you have to call out the name of the field to filter on:
firestore
.collection("projects")
.where("projOwner", isEqualTo: id)
If you have 10 or less share IDs in the list, you can use an "in" query to find matches from projects, and it will not work with any more.
firestore
.collection("projects")
.where("projOwner", whereIn: listOfIds)
So, if you think the list could ever be larger than 10, you should just start by performing individual queries for each share ID.
if 'arrayContains' is not working try 'whereIn'.
var citiesRef = db.collection("projects");
citiesRef.where(FieldPath.documentId, whereIn: ['project1id',
'project2id']);

How can I use multiple order by in real time database flutter to order data by specific field? [duplicate]

This question already has answers here:
Query based on multiple where clauses in Firebase
(8 answers)
Closed 2 years ago.
I am trying to short "realtime database" result according to "date" in flutter. But I cant use multiple orderByChild('child_name'). It throw an error. My code is
final String path = 'jsondata';
final _dbRef = FirebaseDatabase.instance.reference();
_dbRef.child(path)
.orderByChild('trade_code').equalTo('GP')
.once()
.then((DataSnapshot snapshot) {
snapshot.value.forEach((key, value) {
print(value);
});
});
The result is
Result
Now I want to sort the data by Date.
How can I do that?
It's not possible to use multiple oder at the same time in Firebase Realtime Database. Please check the following doc:
Firebase Realtime Database Query
To achieve that type of complex query I prefer that you should migrate from the Realtime Database to Firebase Cloud Firestore. Check the following resource:
Simple and Complex Dynamic Query in Could Firestore
Your Firestore instance would be:
FirebaseFirestore.instance
.collection('products')
.where('trade_code', isEqualTo: 'GP')
.orderBy('date')

Resources