I have a doc tree which looks like:
connections(collection):
connection1(docId):
...fields...
intentItems(subcollection):
intentItem1(docId):
...fields...
intentItem2(docId):
...fields...
connection2(docId):
...fields...
intentItems(subcollection):
intentItem3(docId):
...fields...
intentItem4(docId):
...fields...
As an admin, I want to read an intentItem by id without knowing its connection id.
I tried;
import {doc, documentId, FieldPath} from "#firebase/firestore";
import {query, where} from "firebase/firestore";
//FirebaseError: Invalid query. When querying a collection group by documentId(), the value provided must result in a valid document path, but 'XXXX' is not because it has an odd number of segments (1).
query(collectionGroup(db, Collections.intentItems), where(documentId(), "==", term))
//this returns with empty (** used as wildcard in rules)
useDocument(doc(db, Collections.connections, '**', Collections.intentItems, term))
Do I really need to index an id field in the intentItems if I want to get them back as a result?
Each entry in a Firestore index has to be unique. For indexes on a single collection, it automatically adds the document ID to ensure this. But in a collection group index, multiple documents might have the same ID. That's why, in a collection group index Firestore actually stores the entire document path instead of just the document ID.
o that means that this code won't work:
where(documentId(), "==", term)
As a workaround I recommend storing the document ID in the document itself too, creating a separate index with that value in it, and then filtering on that field rather than the built in documentId().
Related
I wants to achieve one query which i'm trying for few hours in FireStore Database, Please check the below image,
The Query I want to do is, In the document which I marked, will have a list of group id (combination of 2 userIds in each , userId1-userId2), I want to query this document by having one userId that contains in the group id (before or after hyphen) and returns a list of snapshots , which should be used for StreamBuilder in a list widget.
For Example:
I may have 'abcdefghijkl' userId, I want to check each document ID that contains this userId, and returns a list of snapshots which matches.
Thanks in Advance!
I don't think the query you want is possible, since there is no operation to check if a document id contains something. I would recommend adding a participants array to the document and than use an array-contains query, see also here.
There are several ways to achieve what you're after - a list of users relating to a given document - but I think you should rethink your data structure first. Each message document should have a users field that is an array of Firestore document IDs which would contain 1 or more document IDs of the users that this message relates to.
With that, you can easily query the database for all messages where a given user is referenced:
final messages = db
.collection('messages')
.where('users', arrayContains: userId)
.get();
BTW, to take things a step further, I would structure my data like this:
user {
displayName: '',
email: '',
messages: [
{
authorId: userId,
content: '',
users: [userId, ...],
sentOn: '',
},
...
]
}
With this you can do two things:
Fetch all messages created by the user:
final userMessages = db.doc(userId).collection('messages').get();
Fetch all messages where user participated:
final allUserMessages = db
.collectionGroup('messages')
.where('users', arrayContains: userId)
.get();
Check out the Firestore docs, as they have plenty of examples there.
We have a firestore collection, where each document has only one field names.
names contains a map.
Now if, I just want to update a single key value pair in that map, is there a way, other than:
await FirebaseFirestore.instance
.collection(namesCollectionName)
.doc(docId)
.update(savedNames.toJson())
.whenComplete(() => {developer.log("Update saved names success")})
.catchError((error) {
developer.log("Update saved names failed: $error");
throw Exception("Update saved names failed: $error");
});
This code updates the entire map.
I am not sure if there is a way to update just a key value pair. I felt it would be more efficient!
Firestore processes each entries in the map you pass as a set operation on that field.
If you want to update nested fields use . notation to mark that field. So say you store the full name for each user keyed on the Stack Overflow ID as a map under the names field, that'd be:
users
.doc('ABC123')
.update({'names.13076945': 'Nithin Sai'})
If your names field is an array and you want to add a certain name if it doesn't exist in there yet, that'd be an array-union, which looks like this:
users
.doc('ABC123')
.update({'names': FieldValue.arrayUnion(['Nithin Sai'])});
'chatrooms' collection is include documents for example document name is 'PNJAHph61ZStU7IANgBfXAwW66l2-e8GhTlpLyWSdmmBuMlyrfgiJYlI3'
'PNJAHph61ZStU7IANgBfXAwW66l2-e8GhTlpLyWSdmmBuMlyrfgiJYlI3' document include 'messeges' document and 'messeges' document include sub document
I need to get the document name list include in the 'chatrooms' collection.
In a normal case, this function works like that but in nested case, it does not work
firebase.firestore().collection("chatrooms")
.onSnapshot((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(doc.data()); // For data inside doc
console.log(doc.id); // For doc id
}
)});
You will need to create a symbiotic link through data aggregation, as paths in the collection and sub-collections are not linked beyond the name path reference. Additionally, you cannot simply fetch all document names in a collection without reading all the document's data() which would incur reads with billing
so if you need a list of all names, you must create an array of all sub-collection names in the parent document or in a dedicated document called _index
I am very new in this firestorm and database management.
In my code, there are plenty of group documents in a groups collection
Now what I want to do is, show a person from users collection the specific groups he is connected to.
here is how the groups uids look:
here is how the document of user looks:
The code I use to create the group document is this
after creating the document I add the uid of the new document to the user's array called groups.
Future createNewGroupData(String groupName) async {
String _userID = await getUID();
return await groupCollection.add({
'creatorUID': _userID,
'groupName': groupName,
'teachers': [_userID],
}).then((ref) => {
userCollection.document(_userID).updateData({'groups': FieldValue.arrayUnion([ref.documentID])})
});
this is the structure of how I create the document for each user,
Future updateUserData(int avatarID, String firstName, String lastName, String status, List groups, String school) async {
return await userCollection.document(uid).setData({
'avatarID': avatarID.round(),
'firstName': firstName,
'lastName': lastName,
'status': status,
'groups': groups,
'school': school,
});
}
How I implemented that was when the user was added to a group. The uid of that group was appended in an array under that user's documents.
Now what I want to do is get a stream of snapshots of the groups only uids are present in that user's array. I can not really find any way to implement that.
If I understand correctly you want to load the group documents whose document ID matches what you find in the groups field of a user. If that is the case, you are looking for a combination of FieldPath.documentId and an in query.
Something like:
Firestore.instance.collection('groups').where(FieldPath.documentId, whereIn: listOfUids)
As shown in the Firestore documentation on query limitations this will only work for up to 10 document IDs:
Cloud Firestore provides limited support for logical OR queries. The in and array-contains-any operators support a logical OR of up to 10 equality (==) or array-contains conditions on a single field. For other cases, create a separate query for each OR condition and merge the query results in your app.
If you have more document IDs, you will need to fire a separate query for each (up to) 10.
Also see:
Flutter Firebase get documents by array of IDs
Here is a sample of my Firebase data:
I need to be able to search userFavorites for a given user (here, afaapy...) and return the results ordered by the values (timestamps) to get all the user's favorites in order of the date added to the database.
I can search by key as follows, and retrieve all favorites for the given user:
databaseRef.child("userFavorites").queryOrderedByKey().queryEqual(toValue: user.uid).observe(...)
But these favorties are ordered by their keys. If I try to order by value as follows, I get "Cannot use multiple queryOrderedBy calls!":
databaseRef.child("userFavorites").queryOrderedByKey().queryEqual(toValue: user.uid).queryOrderedByValue().observe(...)
How can I retrieve the favorites for a given user sorted by their value?
Second question: is there an easier way to retrieve data in the order it was added to the database?
You can't order the same ref multiple times as documented here
When you use a order or a filter method, it returns a Query Interface. See it as a filtered reference containing only a subset of the original data. It means that
databaseRef.child("userFavorites").orderByKey().equalTo(user.uid)
will not return userFavorite/${user.uid} but userFavorite filtered to show only the user.uid entry. You can see it by doing
databaseRef.child("userFavorites").orderByKey().equalTo(user.uid).ref.key
That should return 'userFavorites'
In your case, I see two options:
Keep going with orderByKey().equalTo() and sort the results yourself
Or use directly child() to get the user, then sort via Firebase (and don't forget to use the Firebase's snapshot.forEach to be sure you get the data in the query order):
databaseRef.child(`userFavorites/${user.uid}`).orderByValue().once('value', (snapshot) => {
if (snapshot.exists()) {
snapshot.forEach((child) => {
console.log(`${child.key}: ${child.val()}`)
})
}
})