Firebase - get posts without which I voted - firebase

I have this data model.
/tests/testId
{
"photos":{
79075240-f6c3-11ea-9d76-c328c656dbfc:{
"url":"",
"votes":0
},
7a394290-f6c3-11ea-bd51-5d216a9dfad9:{
"url":"urlperPhoto"
"votes":0
}
},
"moderated":false,
"owner":o8SIEjIByyaNciEgCFH5Kfh4ngh2,
"active":false,
"votes":0
}
/tests/testId/votes
{
photoId: 'xxx',
birthday: null,
sex: false,
votedDate: null
}
I would like to get a list of posts without which I voted. Because I have voted in other collections so I can add additional field for the post model.
Example:
votedUsers: [user1, user2, user3] or votedUsers: {user1: true, user2: true}
But... I don't have in firebase filter like "not exists". How can I display posts for the user, without this which he voted?

This sort of query is not possible with Firestore, as there are no indexes for data that doesn't exist. You can only query for data that does exist, and is indexed. This means that you will need to execute one query to get some possible items that the user has not voted on, then compare that to the results of another query that checks to see if that user has voted on, and remove those from the result set. Yes, this is difficult, and potentially expensive. But this is just not the sort of problem that Firestore is good at.
You might want to consider using another data along with Firestore in order to maintain this sort of relationship between users and things they have not yet seen or done. (It just won't scale like Firestore.)
See also:
Firebase Firestore Structure for getting un-seen trending posts - Social
How to query Cloud Firestore for non-existing keys of documents

Related

How to combine multiple firebase docs to get a combined result?

In my firebase db I have 3 collections:
Users
{user_id}: {name: "John Smith"}
Items
{item_id}: {value: 12345}
Actions
{action_id}: {action: "example", user: {user_id}, items:{item_id}}
Basically, instead of storing the Users and Items under the Actions Collection, I just keep an ID. But now I need a list of all actions and this also needs info from the Users and Items Collection. How can I efficiently query firebase so I can get a result that looks like this:
{
action: "example",
user: {
name: "John Smith"
},
item: {
value: 1234
}
}
Unfortunately, there is no such thing in firebase or a similar database, basically, you are looking for a traditional join, which is no recommended thing to do in a NoSQL database.
If you want to do it in firebase, you will need:
Get the element you are looking for from your main collection Actions in this case.
Then you need to do another call to the Items collections where item_id == action.item_id.
Then assign in the actions["Item"] = item_gotten.
This is not a recommended use as I said, usually, when you are using a NoSQL Database you are expecting a denormalize structure, from your application you need to save the whole Item, in the Action JSON, and also in the Item. Yes, you will have duplicate data but this is fine for this kind of model. also you shouldn't expect too many changes in one specific object within your whole object key If you are managing a big set of changes you could be using the incorrect kind of DB.
For aggregation queries reference, you might check: https://firebase.google.com/docs/firestore/solutions/aggregation

Firebase database check if element exists in a ListField in Flutter

I have a real-time database on firebase which consists of ListFields. Among these fields, one field, participants is a list of strings and two usernames. I want to make a query to firebase database such that it will return the documents in which a particular username is present in the participants list.
The structure of my document is as follows :
I want to make a query such that Firebase returns all the documents in which the participants list consists aniruddh. I am using Flutter with the flutterfire plugins.
Your current data structure makes it easy to find the participants for a conversation. It does however not make it easy to find the conversations for a user.
One alternative data structure that makes this easier is to store the participants in this format:
imgUrls: {},
participants: {
"aniruddh": true,
"trubluvin": true
}
Now you can technically query for the the conversations of a user with something like:
db.child("conversations").orderByChild("participants/aniruddh").equalTo(true)
But this won't scale very well, as you'll need to define an index for each user.
The proper solution is to add a second data structure, known as an inverted index, that allows the look up of conversations for a user. In your case that could look like this:
userConversations: {
"aniruddh": {
"-LxzV5LzP9TH7L6BvV7": true
},
"trubluvin": {
"-LxzV5LzP9TH7L6BvV7": true
}
}
Now you can look up the conversations that a user is part of with a simple read operation. You could expand this data structure to contain more information on each conversation, such as the information you want to display in your list view.
Also see my answer heres:
Firebase query if child of child contains a value (for more explanation on why the queries won't work in your current structure, and why they won't scale in the first structure in my answer).
Best way to manage Chat channels in Firebase (for an alternative way of naming the chat rooms).

Query by array item and other fields at once in Firestore

I had to rephrase this question since it was a bit misleading (my fault).
Here is my dilemma, let's say I have a party collection:
parties {
status: "open",
invitees: [56486,68978,897650], # user ids of invited users
scheduled_at: 1948089050 # timestamp
}
I'd like to query only "open" parties, that I'm invited to (my user id in the invitees array), and sorted by scheduled_at
I could solve the first part of querying the array by turning it into a hash (thanks to #renaud and #james poag):
parties {
status: "open",
invitees: {
56486: true,
68978: true,
897650: true
}
scheduled_at: 1948089050
}
Now performing this:
db.collection('parties').where('status', '==', 'open').where('invitees.56486', '==', true').orderBy('scheduled_at')
Results in a firebase error asking me to make a composite index for status + invitees.56486 + scheduled_at. as you can see it's impractical for me to add an index for each user id.
Any ideas?
It looks like you're trying to make a query against a schema that doesn't really support that query. You're going to have to adjust your schema (possibly duplicating data between collections) to support your intended query. This sort of practice is normal for NoSQL type databases.
You're going to need a new collection that relates a single party with a single invitee, one for each combination, that effectively serves as a "join" between them:
party-invitees
- party_id
- party_status ("open")
- party_scheduled_at
- attendee_id
Now you can find out which open parties an attendee is invited to:
db.collection('party-invitees')
.where('party_status', '==', 'open')
.where('attendee_id', '==', 'whatever')
.orderBy('party_scheduled_at')
Bear in mind that you'll have to change this collection along with any other collections with the same data as they change. Fortunately, batch writes and transactions make this easier to do atomically.

firestore: representing a relationship

In firestore i have a collection called things.
Each thing is owned by a user.
Each thing can be shared by the owner with other specified users.
the structure of thing looks something like
{
id: "thing01",
sharedWith: {
"user1": true,
"user2": true,
},
dtCreated: 3458973948
}
When I want to retrieve all thing objects that are shared with user1, ordered by dtCreated desc,
i can't do this without having to create an index on things.thing.user1
i.e. for every unique userid i have to create an index on the things collection.
Obviously this is not practical. The docs talk about using full text search for this, but this doesn't seem like a problem we would want to use full text search for.
Is there a different way i should be structuring the data to achieve what i want?
Is firestore just the wrong technology choice for this?
It's working very well for storing the thing objects themselves.
---- update ----
this question is not a real duplicate of Firestore: Working with nested single queries because the answer provided there is very specific to the OP's context.

Cloud Firestore: Query secured documents by field content

EDIT: Seems to be an open issue in Firestore. Also see this post.
In Google Cloud Firestore, I want to model a collection of groups. Each group contains a name, the list of it's users and some secretGroupData. For me, the natural way to do this would be:
/groups
/group1 {
name: "Group 1"
users: { //object can be queried, simple array not
"user1": true,
"user5": true
}
secretGroupData: ...
}
/group2 { ... }
Given a user like user1, I want to query all groups he is member of. This query works fine:
groupsRef.where("users.user1", "==", true)
However, I want to secure the group data. This query only works, when all groups are readable for all users. When I protect the group to be readable only by the group members, by the rule
match /groups/{groupId} {
allow read: if resource.data.users[request.auth.uid] == true;
}
the above query does not work any more, because as soon as it sees a group where the current user is not a member of, read access is denied and the whole query fails.
What is the best solution for this problem in Firestore? Should I
tell Firestore to return only the allowed groups and ignore the other ones, instead of throwing an error? If so, how can I achieve this?
make the groups readable for all users and move the secretGroupData into subcollections, where I can then restrict the access to just the group members
add redundancy by adding the IDs of all groups of a user into the user's profile document (/users/user1/groupIds: ["group1"]), so I know the groups beforehand and can query them by ID
use a totally different solution?
Thank you very much for your ideas.

Resources