2 years ago
#50661

Jonathan
Missing results in Firebase array-contains query with objects
I'm having a weird issue where I'm querying my user table and depending on a whether the user doing the query has the field "group" filled it will either return all users in that group when querying on that field or only the active user when he is part of that group.
export type UserFilter = {
uids?: string[];
organizationId?: AppUser['organizationId'];
teacher?: PartialUserRef;
group?: PartialGroupRef;
};
getUsers(userFilter?: UserFilter) {
return this.afs
.collection<DbUser>(constants.dbCollections.users, (ref) => {
let query = ref.orderBy('name');
if (userFilter?.organizationId) {
query = query.where(
'organizationId',
'==',
userFilter.organizationId
);
}
if (userFilter?.uids) {
query = query.where('uid', 'in', userFilter.uids);
} else {
// Only one array-contains is allowed per query
if (userFilter?.group) {
query = query.where('groups', 'array-contains', userFilter.group);
} else if (userFilter?.teacher) {
query = query.where(
'teachers',
'array-contains',
userFilter.teacher
);
}
}
return query;
})
.snapshotChanges()
.pipe(
map((dbUsers) => dbUsers.map((dbUser) => dbUser.payload.doc.data())),
takeUntil(this.afAuth.authState.pipe(first((user) => !user)))
);
}
My payload for the user filter is exactly the same in both scenarios:
{
"uids": null,
"organizationId": "996",
"teacher": null,
"group": {
"id": "dg8wMCf0mkyhsVoCdhBp",
"name": "A"
}
}
So when the group in the filter exists on the user, the query only returns that user instead of the full group.
My Firestore security rules show no denies:
match /users/{userId} {
// Allow users to read their own user data.
allow read: if userId() == userId;
}
match /users/{userId} {
// Allow teachers to get user data if they belong to the same organization.
// This disallows reads when users have no organization set.
allow read: if isTeacher() && resource.data.organizationId == userOrganizationId(request.auth.uid);
}
edit: even when I allow all reads on the table the issue persists so this this is not likely the cause
Another idea is that it is related to indexes but I find that strange since the query payload does not change. This should be the relevant index though:
{
"collectionGroup": "users",
"queryScope": "COLLECTION",
"fields": [
{
"fieldPath": "groups",
"arrayConfig": "CONTAINS"
},
{
"fieldPath": "organizationId",
"order": "ASCENDING"
},
{
"fieldPath": "name",
"order": "ASCENDING"
}
]
}
So how and why is the group field on the searching user affecting my results?
EDIT:
To clarify what the data looks like and what is returned
Correct result: the searching user is not part of group A. All users of group A are returned.
[
{
"roles": [
3
],
"teachers": [
{
"uid": "5gd3sVyBkaO4oOf4Q0tBoNDJnnH2",
"name": "Jonathan"
}
],
"email": "Asa.Dorsey@dummy.com",
"createdDate": "2021-10-13T11:31:03.821Z",
"uid": "dummy5",
"groups": [
{
"id": "dg8wMCf0mkyhsVoCdhBp",
"name": "A"
}
],
"organizationId": "996",
"name": "Asa Dorsey"
},
{
"organizationId": "996",
"roles": [
3
],
"teachers": [
{
"uid": "5gd3sVyBkaO4oOf4Q0tBoNDJnnH2",
"name": "Jonathan"
}
],
"createdDate": "2021-10-13T11:31:03.820Z",
"name": "Barnaby Allison",
"email": "Barnaby.Allison@dummy.com",
"groups": [
{
"id": "dg8wMCf0mkyhsVoCdhBp",
"name": "A"
}
],
"uid": "dummy1"
},
...
]
Incorrect result: the logged in user is a part of group A. Only the user himself is returned.
[
{
"createdDate": "2021-11-29T11:08:59Z",
"uid": "thiuoKkwjd745hcCsAeakGgssYs1",
"organizationId": "996",
"name": "Jonathan (admin)",
"firstName": "Jonathan",
"groups": [
{
"name": "A",
"id": "dg8wMCf0mkyhsVoCdhBp"
}
],
"emailVerified": true,
"roles": [
0,
1
],
"lastName": "(admin)",
}
]
Note how "name" and "id" fields appear in different order here, this might be relevant. The groups are assigned with the same method so it should not be in different order...
export const getGroupRef = (group: Group): GroupReference => ({
id: group.id,
name: group.name,
});
...
return admin
.firestore()
.collection(constants.dbCollections.users)
.doc(uid)
.update({
groups: firestore.FieldValue.arrayUnion(getGroupRef(group)) as any,
} as Partial<DbUser>);
typescript
firebase
google-cloud-firestore
angularfire2
0 Answers
Your Answer